Imported Upstream version 3.22.0 upstream/3.22.0
authorJinWang An <jinwang.an@samsung.com>
Tue, 27 Dec 2022 08:20:04 +0000 (17:20 +0900)
committerJinWang An <jinwang.an@samsung.com>
Tue, 27 Dec 2022 08:20:04 +0000 (17:20 +0900)
1136 files changed:
Auxiliary/vim/syntax/cmake.vim
CMakeLists.txt
Help/command/cmake_host_system_information.rst
Help/command/configure_file.rst
Help/command/ctest_submit.rst
Help/command/ctest_test.rst
Help/command/file.rst
Help/command/find_package.rst
Help/command/get_property.rst
Help/command/if.rst
Help/command/install.rst
Help/command/list.rst
Help/command/set_property.rst
Help/command/source_group.rst
Help/command/string.rst
Help/command/try_compile.rst
Help/command/try_run.rst
Help/cpack_gen/deb.rst
Help/cpack_gen/nsis.rst
Help/cpack_gen/rpm.rst
Help/dev/documentation.rst
Help/envvar/CMAKE_BUILD_TYPE.rst [new file with mode: 0644]
Help/envvar/CMAKE_CONFIGURATION_TYPES.rst [new file with mode: 0644]
Help/envvar/CMAKE_INSTALL_MODE.rst [new file with mode: 0644]
Help/generator/Visual Studio 10 2010.rst
Help/generator/Visual Studio 15 2017.rst
Help/guide/tutorial/A Basic Starting Point.rst
Help/guide/tutorial/Adding Export Configuration.rst
Help/guide/tutorial/Adding Generator Expressions.rst
Help/guide/tutorial/Adding Support for a Testing Dashboard.rst
Help/guide/tutorial/Adding System Introspection.rst
Help/guide/tutorial/Adding a Library.rst
Help/guide/tutorial/Complete/CMakeLists.txt
Help/guide/tutorial/Installing and Testing.rst
Help/guide/tutorial/Step10/CMakeLists.txt
Help/guide/tutorial/Step11/CMakeLists.txt
Help/guide/tutorial/Step12/CMakeLists.txt
Help/guide/tutorial/Step5/CMakeLists.txt
Help/guide/tutorial/Step6/CMakeLists.txt
Help/guide/tutorial/Step7/CMakeLists.txt
Help/guide/tutorial/Step8/CMakeLists.txt
Help/guide/tutorial/Step8/CTestConfig.cmake [new file with mode: 0644]
Help/guide/tutorial/Step9/CMakeLists.txt
Help/manual/cmake-buildsystem.7.rst
Help/manual/cmake-compile-features.7.rst
Help/manual/cmake-env-variables.7.rst
Help/manual/cmake-generator-expressions.7.rst
Help/manual/cmake-packages.7.rst
Help/manual/cmake-policies.7.rst
Help/manual/cmake-properties.7.rst
Help/manual/cmake-variables.7.rst
Help/manual/ctest.1.rst
Help/manual/presets/schema.json
Help/policy/CMP0127.rst [new file with mode: 0644]
Help/policy/CMP0128.rst [new file with mode: 0644]
Help/prop_gbl/CMAKE_CUDA_KNOWN_FEATURES.rst
Help/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.rst
Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst
Help/prop_sf/VS_SETTINGS.rst
Help/prop_test/ENVIRONMENT.rst
Help/prop_test/ENVIRONMENT_MODIFICATION.rst [new file with mode: 0644]
Help/prop_test/LABELS.rst
Help/prop_tgt/AUTOMOC.rst
Help/prop_tgt/AUTORCC.rst
Help/prop_tgt/AUTOUIC.rst
Help/prop_tgt/CUDA_EXTENSIONS.rst
Help/prop_tgt/CUDA_STANDARD.rst
Help/prop_tgt/CXX_EXTENSIONS.rst
Help/prop_tgt/C_EXTENSIONS.rst
Help/prop_tgt/Fortran_BUILDING_INSTRINSIC_MODULES.rst [new file with mode: 0644]
Help/prop_tgt/HIP_EXTENSIONS.rst [new file with mode: 0644]
Help/prop_tgt/HIP_STANDARD.rst [new file with mode: 0644]
Help/prop_tgt/HIP_STANDARD_REQUIRED.rst [new file with mode: 0644]
Help/prop_tgt/LANG_EXTENSIONS.rst [new file with mode: 0644]
Help/prop_tgt/LANG_STANDARD.rst [new file with mode: 0644]
Help/prop_tgt/LANG_STANDARD_REQUIRED.rst [new file with mode: 0644]
Help/prop_tgt/LINK_WHAT_YOU_USE.rst
Help/prop_tgt/OBJCXX_EXTENSIONS.rst
Help/prop_tgt/OBJC_EXTENSIONS.rst
Help/release/3.21.rst
Help/release/3.22.rst [new file with mode: 0644]
Help/release/index.rst
Help/variable/CMAKE_BUILD_TYPE.rst
Help/variable/CMAKE_CONFIGURATION_TYPES.rst
Help/variable/CMAKE_CUDA_EXTENSIONS.rst
Help/variable/CMAKE_CUDA_STANDARD.rst
Help/variable/CMAKE_CUDA_STANDARD_REQUIRED.rst
Help/variable/CMAKE_CXX_EXTENSIONS.rst
Help/variable/CMAKE_CXX_STANDARD.rst
Help/variable/CMAKE_CXX_STANDARD_REQUIRED.rst
Help/variable/CMAKE_C_EXTENSIONS.rst
Help/variable/CMAKE_C_STANDARD.rst
Help/variable/CMAKE_C_STANDARD_REQUIRED.rst
Help/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.rst
Help/variable/CMAKE_FIND_LIBRARY_SUFFIXES.rst
Help/variable/CMAKE_HIP_EXTENSIONS.rst [new file with mode: 0644]
Help/variable/CMAKE_HIP_STANDARD.rst [new file with mode: 0644]
Help/variable/CMAKE_HIP_STANDARD_REQUIRED.rst [new file with mode: 0644]
Help/variable/CMAKE_LANG_COMPILER_FRONTEND_VARIANT.rst [new file with mode: 0644]
Help/variable/CMAKE_LANG_EXTENSIONS.rst [new file with mode: 0644]
Help/variable/CMAKE_LANG_EXTENSIONS_DEFAULT.rst [new file with mode: 0644]
Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst
Help/variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES.rst
Help/variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG.rst [new file with mode: 0644]
Help/variable/CMAKE_LANG_SIMULATE_ID.rst
Help/variable/CMAKE_LANG_STANDARD.rst [new file with mode: 0644]
Help/variable/CMAKE_LANG_STANDARD_DEFAULT.rst [new file with mode: 0644]
Help/variable/CMAKE_LANG_STANDARD_REQUIRED.rst [new file with mode: 0644]
Help/variable/CMAKE_LINK_WHAT_YOU_USE.rst
Help/variable/CMAKE_LINK_WHAT_YOU_USE_CHECK.rst [new file with mode: 0644]
Help/variable/CMAKE_NETRC.rst
Help/variable/CMAKE_NETRC_FILE.rst
Help/variable/CMAKE_OBJCXX_EXTENSIONS.rst
Help/variable/CMAKE_OBJCXX_STANDARD.rst
Help/variable/CMAKE_OBJCXX_STANDARD_REQUIRED.rst
Help/variable/CMAKE_OBJC_EXTENSIONS.rst
Help/variable/CMAKE_OBJC_STANDARD.rst
Help/variable/CMAKE_OBJC_STANDARD_REQUIRED.rst
Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
Help/variable/CMAKE_REQUIRE_FIND_PACKAGE_PackageName.rst [new file with mode: 0644]
Help/variable/CMAKE_TLS_CAINFO.rst [new file with mode: 0644]
Help/variable/CMAKE_TLS_VERIFY.rst
Help/variable/CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER.rst [new file with mode: 0644]
Help/variable/CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION.rst [new file with mode: 0644]
Help/variable/CMAKE_VS_TARGET_FRAMEWORK_VERSION.rst [new file with mode: 0644]
Help/variable/MSVC_TOOLSET_VERSION.rst
Modules/CMakeASM_MASMInformation.cmake
Modules/CMakeASM_NASMInformation.cmake
Modules/CMakeCCompiler.cmake.in
Modules/CMakeCCompilerId.c.in
Modules/CMakeCInformation.cmake
Modules/CMakeCUDACompiler.cmake.in
Modules/CMakeCUDACompilerId.cu.in
Modules/CMakeCUDAInformation.cmake
Modules/CMakeCXXCompiler.cmake.in
Modules/CMakeCXXCompilerId.cpp.in
Modules/CMakeCXXInformation.cmake
Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
Modules/CMakeDependentOption.cmake
Modules/CMakeDetermineASMCompiler.cmake
Modules/CMakeDetermineCCompiler.cmake
Modules/CMakeDetermineCUDACompiler.cmake
Modules/CMakeDetermineCXXCompiler.cmake
Modules/CMakeDetermineCompilerId.cmake
Modules/CMakeDetermineFortranCompiler.cmake
Modules/CMakeFindBinUtils.cmake
Modules/CMakeFindPackageMode.cmake
Modules/CMakeFortranCompiler.cmake.in
Modules/CMakeFortranCompilerABI.F90 [new file with mode: 0644]
Modules/CMakeFortranInformation.cmake
Modules/CMakeHIPCompiler.cmake.in
Modules/CMakeHIPCompilerId.hip.in
Modules/CMakeHIPInformation.cmake
Modules/CMakeOBJCCompiler.cmake.in
Modules/CMakeOBJCCompilerId.m.in
Modules/CMakeOBJCInformation.cmake
Modules/CMakeOBJCXXCompiler.cmake.in
Modules/CMakeOBJCXXCompilerId.mm.in
Modules/CMakeOBJCXXInformation.cmake
Modules/CMakeSwiftInformation.cmake
Modules/CMakeTestFortranCompiler.cmake
Modules/CMakeTestHIPCompiler.cmake
Modules/CPackIFW.cmake
Modules/CheckCXXSymbolExists.cmake
Modules/CheckFortranFunctionExists.cmake
Modules/CheckLanguage.cmake
Modules/CheckLinkerFlag.cmake
Modules/CheckSymbolExists.cmake
Modules/Compiler/ARMClang-C.cmake
Modules/Compiler/ARMClang-CXX.cmake
Modules/Compiler/AppleClang-CXX.cmake
Modules/Compiler/CMakeCommonCompilerMacros.cmake
Modules/Compiler/Clang-C.cmake
Modules/Compiler/Clang-CXX.cmake
Modules/Compiler/IAR-ASM.cmake
Modules/Compiler/IAR-C.cmake
Modules/Compiler/IAR-CXX.cmake
Modules/Compiler/IAR-DetermineCompiler.cmake
Modules/Compiler/IAR.cmake
Modules/Compiler/Intel-C.cmake
Modules/Compiler/Intel-CXX.cmake
Modules/Compiler/IntelLLVM-C.cmake
Modules/Compiler/IntelLLVM-CXX.cmake
Modules/Compiler/MSVC-C.cmake
Modules/Compiler/MSVC-CXX.cmake
Modules/Compiler/NVHPC.cmake
Modules/Compiler/PGI.cmake
Modules/CompilerId/VS-10.csproj.in
Modules/ExternalProject.cmake
Modules/FetchContent.cmake
Modules/FindBLAS.cmake
Modules/FindCUDAToolkit.cmake
Modules/FindFLTK.cmake
Modules/FindGLUT.cmake
Modules/FindHDF5.cmake
Modules/FindICU.cmake
Modules/FindJasper.cmake
Modules/FindLAPACK.cmake
Modules/FindMPI.cmake
Modules/FindMPI/test_mpi.c
Modules/FindMatlab.cmake
Modules/FindPatch.cmake
Modules/FindPkgConfig.cmake
Modules/FindThreads.cmake
Modules/FindX11.cmake
Modules/GNUInstallDirs.cmake
Modules/GetPrerequisites.cmake
Modules/GoogleTest.cmake
Modules/GoogleTestAddTests.cmake
Modules/InstallRequiredSystemLibraries.cmake
Modules/Internal/CPack/CPackDeb.cmake
Modules/Internal/CPack/CPackRPM.cmake
Modules/Internal/CPack/NSIS.template.in
Modules/Internal/OSRelease/010-TryOldCentOS.cmake [new file with mode: 0644]
Modules/Internal/OSRelease/020-TryDebianVersion.cmake [new file with mode: 0644]
Modules/Platform/Android-Determine.cmake
Modules/Platform/Windows-Clang.cmake
Modules/Platform/Windows-GNU.cmake
Modules/Platform/Windows-Intel-C.cmake
Modules/Platform/Windows-Intel-CXX.cmake
Modules/Platform/Windows-IntelLLVM.cmake
Modules/UseSWIG.cmake
Modules/VTKCompatibility.cmake
Source/CMakeLists.txt
Source/CMakeVersion.cmake
Source/CPack/IFW/cmCPackIFWCommon.cxx
Source/CPack/IFW/cmCPackIFWCommon.h
Source/CPack/IFW/cmCPackIFWGenerator.cxx
Source/CPack/IFW/cmCPackIFWInstaller.cxx
Source/CPack/IFW/cmCPackIFWPackage.cxx
Source/CPack/IFW/cmCPackIFWRepository.cxx
Source/CPack/OSXScriptLauncher.cxx
Source/CPack/WiX/cmCPackWIXGenerator.cxx
Source/CPack/cmCPackArchiveGenerator.cxx
Source/CPack/cmCPackBundleGenerator.cxx
Source/CPack/cmCPackCygwinBinaryGenerator.cxx
Source/CPack/cmCPackCygwinSourceGenerator.cxx
Source/CPack/cmCPackDebGenerator.cxx
Source/CPack/cmCPackDebGenerator.h
Source/CPack/cmCPackDragNDropGenerator.cxx
Source/CPack/cmCPackExternalGenerator.cxx
Source/CPack/cmCPackFreeBSDGenerator.cxx
Source/CPack/cmCPackGenerator.cxx
Source/CPack/cmCPackGenerator.h
Source/CPack/cmCPackNSISGenerator.cxx
Source/CPack/cmCPackNuGetGenerator.cxx
Source/CPack/cmCPackOSXX11Generator.cxx
Source/CPack/cmCPackPKGGenerator.cxx
Source/CPack/cmCPackPackageMakerGenerator.cxx
Source/CPack/cmCPackProductBuildGenerator.cxx
Source/CPack/cmCPackProductBuildGenerator.h
Source/CPack/cmCPackRPMGenerator.cxx
Source/CPack/cmCPackSTGZGenerator.cxx
Source/CPack/cpack.cxx
Source/CTest/cmCTestBuildCommand.cxx
Source/CTest/cmCTestBuildHandler.cxx
Source/CTest/cmCTestConfigureCommand.cxx
Source/CTest/cmCTestGIT.cxx
Source/CTest/cmCTestGenericHandler.cxx
Source/CTest/cmCTestGenericHandler.h
Source/CTest/cmCTestHandlerCommand.cxx
Source/CTest/cmCTestMemCheckHandler.cxx
Source/CTest/cmCTestMemCheckHandler.h
Source/CTest/cmCTestMultiProcessHandler.cxx
Source/CTest/cmCTestRunTest.cxx
Source/CTest/cmCTestRunTest.h
Source/CTest/cmCTestScriptHandler.cxx
Source/CTest/cmCTestStartCommand.cxx
Source/CTest/cmCTestSubmitCommand.cxx
Source/CTest/cmCTestSubmitHandler.cxx
Source/CTest/cmCTestTestCommand.cxx
Source/CTest/cmCTestTestHandler.cxx
Source/CTest/cmCTestTestHandler.h
Source/CTest/cmCTestTestMeasurementXMLParser.cxx [new file with mode: 0644]
Source/CTest/cmCTestTestMeasurementXMLParser.h [new file with mode: 0644]
Source/CTest/cmCTestUpdateCommand.cxx
Source/CTest/cmCTestUpdateHandler.cxx
Source/CTest/cmCTestUpdateHandler.h
Source/CTest/cmCTestVC.cxx
Source/CursesDialog/cmCursesCacheEntryComposite.cxx
Source/CursesDialog/cmCursesMainForm.cxx
Source/LexerParser/cmFortranParser.cxx
Source/LexerParser/cmFortranParser.y
Source/QtDialog/CMakeSetup.cxx
Source/QtDialog/QCMake.cxx
Source/cmAddLibraryCommand.cxx
Source/cmAddTestCommand.cxx
Source/cmAlgorithms.h
Source/cmArchiveWrite.cxx
Source/cmBinUtilsLinuxELFLinker.cxx
Source/cmBinUtilsMacOSMachOLinker.cxx
Source/cmBinUtilsMacOSMachOLinker.h
Source/cmBuildCommand.cxx
Source/cmBuildNameCommand.cxx
Source/cmCMakeHostSystemInformationCommand.cxx
Source/cmCMakePathCommand.cxx
Source/cmCMakePolicyCommand.cxx
Source/cmCPluginAPI.cxx
Source/cmCTest.cxx
Source/cmCacheManager.cxx
Source/cmCacheManager.h
Source/cmCommand.h
Source/cmCommandArgumentParserHelper.cxx
Source/cmCommonTargetGenerator.cxx
Source/cmCommonTargetGenerator.h
Source/cmComputeLinkDepends.cxx
Source/cmComputeLinkInformation.cxx
Source/cmComputeLinkInformation.h
Source/cmComputeTargetDepends.cxx
Source/cmConditionEvaluator.cxx
Source/cmConditionEvaluator.h
Source/cmConfigure.cmake.h.in
Source/cmCoreTryCompile.cxx
Source/cmCurl.cxx
Source/cmCurl.h
Source/cmCustomCommandGenerator.cxx
Source/cmDefinitions.cxx
Source/cmDefinitions.h
Source/cmDepends.cxx
Source/cmDependsC.cxx
Source/cmDependsFortran.cxx
Source/cmDependsFortran.h
Source/cmELF.cxx
Source/cmELF.h
Source/cmExportBuildFileGenerator.cxx
Source/cmExportBuildFileGenerator.h
Source/cmExportCommand.cxx
Source/cmExportFileGenerator.cxx
Source/cmExportFileGenerator.h
Source/cmExportInstallFileGenerator.cxx
Source/cmExportInstallFileGenerator.h
Source/cmExportLibraryDependenciesCommand.cxx
Source/cmExportTryCompileFileGenerator.cxx
Source/cmExportTryCompileFileGenerator.h
Source/cmExtraCodeBlocksGenerator.cxx
Source/cmExtraCodeLiteGenerator.cxx
Source/cmExtraEclipseCDT4Generator.cxx
Source/cmExtraKateGenerator.cxx
Source/cmExtraSublimeTextGenerator.cxx
Source/cmFileAPICache.cxx
Source/cmFileAPICodemodel.cxx
Source/cmFileAPIToolchains.cxx
Source/cmFileCommand.cxx
Source/cmFileCopier.cxx
Source/cmFileCopier.h
Source/cmFileInstaller.cxx
Source/cmFileInstaller.h
Source/cmFindBase.cxx
Source/cmFindCommon.cxx
Source/cmFindLibraryCommand.cxx
Source/cmFindPackageCommand.cxx
Source/cmForEachCommand.cxx
Source/cmFortranParser.h
Source/cmFortranParserImpl.cxx
Source/cmGeneratorExpressionNode.cxx
Source/cmGeneratorTarget.cxx
Source/cmGeneratorTarget.h
Source/cmGetCMakePropertyCommand.cxx
Source/cmGetDirectoryPropertyCommand.cxx
Source/cmGetFilenameComponentCommand.cxx
Source/cmGetPropertyCommand.cxx
Source/cmGetSourceFilePropertyCommand.cxx
Source/cmGetTargetPropertyCommand.cxx
Source/cmGetTestPropertyCommand.cxx
Source/cmGhsMultiTargetGenerator.cxx
Source/cmGlobalCommonGenerator.cxx
Source/cmGlobalCommonGenerator.h
Source/cmGlobalGenerator.cxx
Source/cmGlobalGenerator.h
Source/cmGlobalGhsMultiGenerator.cxx
Source/cmGlobalJOMMakefileGenerator.cxx
Source/cmGlobalJOMMakefileGenerator.h
Source/cmGlobalNMakeMakefileGenerator.cxx
Source/cmGlobalNMakeMakefileGenerator.h
Source/cmGlobalNinjaGenerator.cxx
Source/cmGlobalNinjaGenerator.h
Source/cmGlobalUnixMakefileGenerator3.cxx
Source/cmGlobalUnixMakefileGenerator3.h
Source/cmGlobalVisualStudio10Generator.cxx
Source/cmGlobalVisualStudio10Generator.h
Source/cmGlobalVisualStudio14Generator.cxx
Source/cmGlobalVisualStudio71Generator.cxx
Source/cmGlobalVisualStudio71Generator.h
Source/cmGlobalVisualStudio7Generator.cxx
Source/cmGlobalVisualStudio7Generator.h
Source/cmGlobalVisualStudio8Generator.cxx
Source/cmGlobalVisualStudio8Generator.h
Source/cmGlobalVisualStudioGenerator.cxx
Source/cmGlobalVisualStudioGenerator.h
Source/cmGlobalVisualStudioVersionedGenerator.cxx
Source/cmGlobalVisualStudioVersionedGenerator.h
Source/cmGlobalXCodeGenerator.cxx
Source/cmGlobalXCodeGenerator.h
Source/cmGraphVizWriter.cxx
Source/cmIncludeCommand.cxx
Source/cmIncludeDirectoryCommand.cxx
Source/cmIncludeExternalMSProjectCommand.cxx
Source/cmIncludeGuardCommand.cxx
Source/cmIncludeRegularExpressionCommand.cxx
Source/cmInstallCommand.cxx
Source/cmInstallMode.h [new file with mode: 0644]
Source/cmInstallSubdirectoryGenerator.cxx
Source/cmInstallTargetGenerator.cxx
Source/cmInstalledFile.cxx
Source/cmLinkDirectoriesCommand.cxx
Source/cmLinkItem.cxx
Source/cmLinkLineDeviceComputer.cxx
Source/cmListCommand.cxx
Source/cmListFileCache.cxx
Source/cmLocalCommonGenerator.cxx
Source/cmLocalGenerator.cxx
Source/cmLocalGenerator.h
Source/cmLocalNinjaGenerator.cxx
Source/cmLocalUnixMakefileGenerator3.cxx
Source/cmLocalUnixMakefileGenerator3.h
Source/cmLocalVisualStudio7Generator.cxx
Source/cmLocalVisualStudioGenerator.cxx
Source/cmLocalVisualStudioGenerator.h
Source/cmMakefile.cxx
Source/cmMakefile.h
Source/cmMakefileExecutableTargetGenerator.cxx
Source/cmMakefileLibraryTargetGenerator.cxx
Source/cmMakefileProfilingData.cxx
Source/cmMakefileTargetGenerator.cxx
Source/cmMarkAsAdvancedCommand.cxx
Source/cmNinjaNormalTargetGenerator.cxx
Source/cmNinjaTargetGenerator.cxx
Source/cmNinjaUtilityTargetGenerator.cxx
Source/cmOptionCommand.cxx
Source/cmOutputConverter.cxx
Source/cmOutputRequiredFilesCommand.cxx
Source/cmParseArgumentsCommand.cxx
Source/cmPolicies.cxx
Source/cmPolicies.h
Source/cmProjectCommand.cxx
Source/cmProperty.h
Source/cmPropertyMap.cxx
Source/cmPropertyMap.h
Source/cmQTWrapCPPCommand.cxx
Source/cmQtAutoGen.cxx
Source/cmQtAutoGen.h
Source/cmQtAutoGenGlobalInitializer.cxx
Source/cmQtAutoGenGlobalInitializer.h
Source/cmQtAutoGenInitializer.cxx
Source/cmQtAutoGenInitializer.h
Source/cmQtAutoGenerator.cxx
Source/cmQtAutoMocUic.cxx
Source/cmRST.cxx
Source/cmRST.h
Source/cmRemoveCommand.cxx
Source/cmRuntimeDependencyArchive.cxx
Source/cmSearchPath.cxx
Source/cmSeparateArgumentsCommand.cxx
Source/cmSetCommand.cxx
Source/cmSetDirectoryPropertiesCommand.cxx
Source/cmSetPropertyCommand.cxx
Source/cmSetSourceFilesPropertiesCommand.cxx
Source/cmSetTestsPropertiesCommand.cxx
Source/cmSiteNameCommand.cxx
Source/cmSourceFile.cxx
Source/cmSourceFile.h
Source/cmStandardLevelResolver.cxx
Source/cmStandardLevelResolver.h
Source/cmState.cxx
Source/cmState.h
Source/cmStateDirectory.cxx
Source/cmStateDirectory.h
Source/cmStatePrivate.h
Source/cmStateSnapshot.cxx
Source/cmStateSnapshot.h
Source/cmStringAlgorithms.cxx
Source/cmStringAlgorithms.h
Source/cmStringCommand.cxx
Source/cmSystemTools.cxx
Source/cmSystemTools.h
Source/cmTarget.cxx
Source/cmTarget.h
Source/cmTargetCompileOptionsCommand.cxx
Source/cmTargetExport.h
Source/cmTargetIncludeDirectoriesCommand.cxx
Source/cmTargetLinkDirectoriesCommand.cxx
Source/cmTargetLinkLibrariesCommand.cxx
Source/cmTargetLinkOptionsCommand.cxx
Source/cmTargetPropCommandBase.cxx
Source/cmTargetPropertyComputer.cxx
Source/cmTargetPropertyComputer.h
Source/cmTest.cxx
Source/cmTest.h
Source/cmTestGenerator.cxx
Source/cmTimestamp.cxx
Source/cmTryRunCommand.cxx
Source/cmUVHandlePtr.h
Source/cmUtilitySourceCommand.cxx
Source/cmValue.cxx [new file with mode: 0644]
Source/cmValue.h [new file with mode: 0644]
Source/cmVariableRequiresCommand.cxx
Source/cmVariableWatchCommand.cxx
Source/cmVisualStudio10TargetGenerator.cxx
Source/cmVisualStudio10TargetGenerator.h
Source/cmWhileCommand.cxx
Source/cmWorkerPool.h
Source/cmXCodeScheme.cxx
Source/cmake.cxx
Source/cmake.h
Source/cmakemain.cxx
Source/cmcmd.cxx
Source/kwsys/Status.hxx.in
Source/kwsys/SystemInformation.cxx
Source/kwsys/SystemTools.cxx
Source/kwsys/testDirectory.cxx
Source/kwsys/testStatus.cxx
Source/kwsys/testSystemTools.cxx
Templates/MSBuild/FlagTables/v143_Link.json
Tests/CMakeLib/testRST.expect
Tests/CMakeLib/testRST.rst
Tests/CMakeLib/testUVRAII.cxx
Tests/CMakeLists.txt
Tests/CMakeTests/CMakeLists.txt
Tests/CPackNSISGenerator/CMakeLists.txt
Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
Tests/CTestTestSerialInDepends/test.ctest
Tests/Cuda/CMakeLists.txt
Tests/Cuda/ConsumeCompileFeatures/CMakeLists.txt [deleted file]
Tests/Cuda/ConsumeCompileFeatures/main.cu [deleted file]
Tests/Cuda/ConsumeCompileFeatures/static.cpp [deleted file]
Tests/Cuda/ConsumeCompileFeatures/static.cu [deleted file]
Tests/EnforceConfig.cmake.in
Tests/Environment/CMakeLists.txt
Tests/Environment/check_mod.cmake [new file with mode: 0644]
Tests/FindBLAS/CMakeLists.txt
Tests/FindBLAS/Test/CMakeLists.txt
Tests/FindBLAS/Test/main.c
Tests/FindBLAS/add_BLAS_LAPACK_tests.cmake [new file with mode: 0644]
Tests/FindGLUT/CMakeLists.txt [new file with mode: 0644]
Tests/FindGLUT/Test/CMakeLists.txt [new file with mode: 0644]
Tests/FindGLUT/Test/main.c [new file with mode: 0644]
Tests/FindJasper/CMakeLists.txt [new file with mode: 0644]
Tests/FindJasper/Test/CMakeLists.txt [new file with mode: 0644]
Tests/FindJasper/Test/main.c [new file with mode: 0644]
Tests/FindLAPACK/CMakeLists.txt
Tests/FindLAPACK/Test/CMakeLists.txt
Tests/FindLAPACK/Test/main.c
Tests/FindMatlab/targets_checks/CMakeLists.txt [new file with mode: 0644]
Tests/IncludeDirectories/CMakeLists.txt
Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt
Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp
Tests/IncludeDirectories/SystemIncludeDirectories/imported_consumer.cpp
Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h
Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/CMakeLists.txt
Tests/InstallMode/CMakeLists.txt [new file with mode: 0644]
Tests/InstallMode/README.txt [new file with mode: 0644]
Tests/InstallMode/Subproject.cmake [new file with mode: 0644]
Tests/InstallMode/Test.cmake [new file with mode: 0644]
Tests/InstallMode/subpro_a_static_lib/CMakeLists.txt [new file with mode: 0644]
Tests/InstallMode/subpro_a_static_lib/cmake/PackageConfig.cmake.in [new file with mode: 0644]
Tests/InstallMode/subpro_a_static_lib/include/static_lib.h [new file with mode: 0644]
Tests/InstallMode/subpro_a_static_lib/src/static_lib.cpp [new file with mode: 0644]
Tests/InstallMode/subpro_b_shared_lib/CMakeLists.txt [new file with mode: 0644]
Tests/InstallMode/subpro_b_shared_lib/cmake/PackageConfig.cmake.in [new file with mode: 0644]
Tests/InstallMode/subpro_b_shared_lib/include/shared_lib.h [new file with mode: 0644]
Tests/InstallMode/subpro_b_shared_lib/src/shared_lib.cpp [new file with mode: 0644]
Tests/InstallMode/subpro_c_nested_lib/CMakeLists.txt [new file with mode: 0644]
Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/CMakeLists.txt [new file with mode: 0644]
Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/cmake/PackageConfig.cmake.in [new file with mode: 0644]
Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/include/c1_lib.h [new file with mode: 0644]
Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/src/c1_lib.cpp [new file with mode: 0644]
Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/CMakeLists.txt [new file with mode: 0644]
Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/cmake/PackageConfig.cmake.in [new file with mode: 0644]
Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/include/c2_lib.h [new file with mode: 0644]
Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/src/c2_lib.cpp [new file with mode: 0644]
Tests/InstallMode/subpro_d_executable/CMakeLists.txt [new file with mode: 0644]
Tests/InstallMode/subpro_d_executable/src/main.cpp [new file with mode: 0644]
Tests/InstallMode/superpro/CMakeLists.txt [new file with mode: 0644]
Tests/InstallMode/superpro/file_copy.txt [new file with mode: 0644]
Tests/InstallMode/superpro/file_copy_file.txt [new file with mode: 0644]
Tests/InstallMode/superpro/file_create_link_symbolic.txt [new file with mode: 0644]
Tests/InstallMode/superpro/file_install.txt [new file with mode: 0644]
Tests/MSManifest/Subdir/CMakeLists.txt
Tests/MSManifest/Subdir2/CMakeLists.txt
Tests/Qt6Autogen/CMakeLists.txt [new file with mode: 0644]
Tests/QtAutogen/AutogenCoreTest.cmake
Tests/QtAutogen/AutogenGuiTest.cmake
Tests/QtAutogen/AutogenOriginDependsOff/CMakeLists.txt
Tests/QtAutogen/AutogenOriginDependsOn/CMakeLists.txt
Tests/QtAutogen/AutogenTargetDepends/CMakeLists.txt
Tests/QtAutogen/Complex/CMakeLists.txt
Tests/QtAutogen/Complex/codeeditor.cpp
Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
Tests/QtAutogen/GlobalAutogenTarget/GAT/CMakeLists.txt
Tests/QtAutogen/MacOsFW/CMakeLists.txt
Tests/QtAutogen/MacOsFW/src/CMakeLists.txt
Tests/QtAutogen/MacOsFW/test/CMakeLists.txt
Tests/QtAutogen/ManySources/CMakeLists.txt
Tests/QtAutogen/MocCMP0071/CMakeLists.txt
Tests/QtAutogen/MocCMP0071/NEW/CMakeLists.txt
Tests/QtAutogen/MocCMP0071/OLD/CMakeLists.txt
Tests/QtAutogen/MocCMP0100/CMakeLists.txt
Tests/QtAutogen/MocCMP0100/NEW/CMakeLists.txt
Tests/QtAutogen/MocCMP0100/OLD/CMakeLists.txt
Tests/QtAutogen/MocInclude/CMakeLists.txt
Tests/QtAutogen/MocIncludeSymlink/CMakeLists.txt
Tests/QtAutogen/MocMacroName/CMakeLists.txt
Tests/QtAutogen/MocOnly/CMakeLists.txt
Tests/QtAutogen/MocOptions/CMakeLists.txt
Tests/QtAutogen/MocOsMacros/CMakeLists.txt
Tests/QtAutogen/MocSkipSource/CMakeLists.txt
Tests/QtAutogen/ObjectLibrary/CMakeLists.txt
Tests/QtAutogen/ObjectLibrary/a/CMakeLists.txt
Tests/QtAutogen/Parallel/CMakeLists.txt
Tests/QtAutogen/Parallel1/CMakeLists.txt
Tests/QtAutogen/Parallel2/CMakeLists.txt
Tests/QtAutogen/Parallel3/CMakeLists.txt
Tests/QtAutogen/Parallel4/CMakeLists.txt
Tests/QtAutogen/ParallelAUTO/CMakeLists.txt
Tests/QtAutogen/RccEmpty/CMakeLists.txt
Tests/QtAutogen/RccOffMocLibrary/CMakeLists.txt
Tests/QtAutogen/RccOnly/CMakeLists.txt
Tests/QtAutogen/RccSkipSource/CMakeLists.txt
Tests/QtAutogen/RerunMocBasic/CMakeLists.txt
Tests/QtAutogen/RerunMocBasic/MocBasic/CMakeLists.txt
Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt
Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/CMakeLists.txt.in
Tests/QtAutogen/RerunMocOnMissingDependency/CMakeLists.txt
Tests/QtAutogen/RerunMocPlugin/CMakeLists.txt
Tests/QtAutogen/RerunMocPlugin/MocPlugin/CMakeLists.txt
Tests/QtAutogen/RerunRccConfigChange/CMakeLists.txt
Tests/QtAutogen/RerunRccConfigChange/RccConfigChange/CMakeLists.txt
Tests/QtAutogen/RerunRccDepends/CMakeLists.txt
Tests/QtAutogen/RerunRccDepends/RccDepends/CMakeLists.txt
Tests/QtAutogen/RerunUicOnFileChange/CMakeLists.txt
Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/CMakeLists.txt.in
Tests/QtAutogen/StaticLibraryCycle/CMakeLists.txt
Tests/QtAutogen/TestMacros.cmake
Tests/QtAutogen/UicInclude/CMakeLists.txt
Tests/QtAutogen/UicInterface/CMakeLists.txt
Tests/QtAutogen/UicNoGui/CMakeLists.txt
Tests/QtAutogen/UicOnly/CMakeLists.txt
Tests/QtAutogen/UicSkipSource/CMakeLists.txt
Tests/RunCMake/Autogen/CMP0111-imported-target-prelude.cmake
Tests/RunCMake/Autogen/CMakeLists.txt
Tests/RunCMake/Autogen/QtInFunction.cmake
Tests/RunCMake/Autogen/QtInFunctionNested.cmake
Tests/RunCMake/Autogen/QtInFunctionProperty.cmake
Tests/RunCMake/Autogen/RunCMakeTest.cmake
Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/CheckEnvironmentVar-build-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/CheckEnvironmentVar.cmake [new file with mode: 0644]
Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/echo_message.bat [new file with mode: 0755]
Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-NEW-stdout.txt [moved from Tests/RunCMake/CMakeDependentOption/Regex-stdout.txt with 100% similarity]
Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-NEW.cmake [new file with mode: 0644]
Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-WARN-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-WARN-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-WARN.cmake [new file with mode: 0644]
Tests/RunCMake/CMakeDependentOption/Regex-CMP0127-NEW-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakeDependentOption/Regex-CMP0127-NEW.cmake [new file with mode: 0644]
Tests/RunCMake/CMakeDependentOption/Regex-CMP0127-OLD-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakeDependentOption/Regex-CMP0127-OLD.cmake [moved from Tests/RunCMake/CMakeDependentOption/Regex.cmake with 84% similarity]
Tests/RunCMake/CMakeDependentOption/RunCMakeTest.cmake
Tests/RunCMake/CMakeDependentOption/Simple-CMP0127-OLD-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakeDependentOption/Simple-CMP0127-OLD.cmake [new file with mode: 0644]
Tests/RunCMake/CMakeLists.txt
Tests/RunCMake/CPack/RunCMakeTest.cmake
Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake
Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake
Tests/RunCMake/CPack/tests/EXTRA/DEB-stderr.txt
Tests/RunCMake/CPack/tests/MD5SUMS/ExpectedFiles.cmake
Tests/RunCMake/CPack/tests/MD5SUMS/VerifyResult.cmake
Tests/RunCMake/CPack/tests/MD5SUMS/test.cmake
Tests/RunCMake/CommandLine/DeprecateVS10-WARN-OFF.cmake [new file with mode: 0644]
Tests/RunCMake/CommandLine/DeprecateVS10-WARN-ON-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CommandLine/DeprecateVS10-WARN-ON.cmake [new file with mode: 0644]
Tests/RunCMake/CommandLine/EnvBuildType-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CommandLine/EnvBuildType.cmake [new file with mode: 0644]
Tests/RunCMake/CommandLine/EnvBuildTypeIgnore-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CommandLine/EnvBuildTypeIgnore.cmake [new file with mode: 0644]
Tests/RunCMake/CommandLine/EnvConfigTypes-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CommandLine/EnvConfigTypes.cmake [new file with mode: 0644]
Tests/RunCMake/CommandLine/EnvConfigTypesIgnore-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CommandLine/EnvConfigTypesIgnore.cmake [new file with mode: 0644]
Tests/RunCMake/CommandLine/RunCMakeTest.cmake
Tests/RunCMake/CompileFeatures/CMP0128WarnMatch-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CompileFeatures/CMP0128WarnMatch.cmake [new file with mode: 0644]
Tests/RunCMake/CompileFeatures/CMP0128WarnUnset-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CompileFeatures/CMP0128WarnUnset.cmake [new file with mode: 0644]
Tests/RunCMake/CompileFeatures/ExtensionsStandardDefault-build-check.cmake [new file with mode: 0644]
Tests/RunCMake/CompileFeatures/ExtensionsStandardDefault.cmake [new file with mode: 0644]
Tests/RunCMake/CompileFeatures/ExtensionsStandardUnset-build-check.cmake [new file with mode: 0644]
Tests/RunCMake/CompileFeatures/ExtensionsStandardUnset.cmake [new file with mode: 0644]
Tests/RunCMake/CompileFeatures/NoUnnecessaryFlag-build-check.cmake [new file with mode: 0644]
Tests/RunCMake/CompileFeatures/NoUnnecessaryFlag.cmake [new file with mode: 0644]
Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake
Tests/RunCMake/CompileFeatures/compiler_introspection.cmake [new file with mode: 0644]
Tests/RunCMake/CompileFeatures/empty.c
Tests/RunCMake/CompileFeatures/generate_feature_list.cmake [deleted file]
Tests/RunCMake/FetchContent/RunCMakeTest.cmake
Tests/RunCMake/FetchContent/VarPassthroughs.cmake [new file with mode: 0644]
Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_MATCHING_ARGN.cmake [new file with mode: 0644]
Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH-stdout.txt [new file with mode: 0644]
Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH.cmake [new file with mode: 0644]
Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
Tests/RunCMake/FindPkgConfig/dummy-pkg-config.bat
Tests/RunCMake/FindPkgConfig/dummy-pkg-config.sh
Tests/RunCMake/GeneratorExpression/CMP0085-OLD-stderr.txt [new file with mode: 0644]
Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change-basic-stdout.txt [new file with mode: 0644]
Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change-typed-stdout.txt [new file with mode: 0644]
Tests/RunCMake/GoogleTest/GoogleTest-skip-test-stdout.txt [moved from Tests/RunCMake/GoogleTest/GoogleTest-skip-timeout-stdout.txt with 51% similarity]
Tests/RunCMake/GoogleTest/GoogleTest-test3-stdout.txt [new file with mode: 0644]
Tests/RunCMake/GoogleTest/GoogleTest-test4-stdout.txt [new file with mode: 0644]
Tests/RunCMake/GoogleTest/GoogleTest.cmake
Tests/RunCMake/GoogleTest/GoogleTestDiscoveryArgChange.cmake [new file with mode: 0644]
Tests/RunCMake/GoogleTest/RunCMakeTest.cmake
Tests/RunCMake/GoogleTest/fake_gtest.cpp
Tests/RunCMake/Ninja/Qt5AutoMocDeps.cmake [deleted file]
Tests/RunCMake/Ninja/QtAutoMocDeps.cmake [new file with mode: 0644]
Tests/RunCMake/Ninja/QtSubDir1/CMakeLists.txt
Tests/RunCMake/Ninja/QtSubDir2/CMakeLists.txt
Tests/RunCMake/Ninja/QtSubDir3/CMakeLists.txt
Tests/RunCMake/Ninja/RunCMakeTest.cmake
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_target-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_target-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_target-release-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex.cmake
Tests/RunCMake/NinjaMultiConfig/QtX-automoc-check-ninja-stdout.txt [moved from Tests/RunCMake/NinjaMultiConfig/Qt5-automoc-check-ninja-stdout.txt with 100% similarity]
Tests/RunCMake/NinjaMultiConfig/QtX-debug-in-release-graph-build-check.cmake [moved from Tests/RunCMake/NinjaMultiConfig/Qt5-debug-in-release-graph-build-check.cmake with 100% similarity]
Tests/RunCMake/NinjaMultiConfig/QtX.cmake [moved from Tests/RunCMake/NinjaMultiConfig/Qt5.cmake with 77% similarity]
Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
Tests/RunCMake/PrecompileHeaders/PchIncludedAllLanguages.cmake [new file with mode: 0644]
Tests/RunCMake/PrecompileHeaders/PchLibObjLibExe.cmake [new file with mode: 0644]
Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
Tests/RunCMake/PrecompileHeaders/pch-included.c [new file with mode: 0644]
Tests/RunCMake/PrecompileHeaders/pch-included.cpp [new file with mode: 0644]
Tests/RunCMake/PrecompileHeaders/pch.h
Tests/RunCMake/RunCMake.cmake
Tests/RunCMake/UseSWIG/CMP0086-OLD-stderr.txt [new file with mode: 0644]
Tests/RunCMake/VS10Project/RunCMakeTest.cmake
Tests/RunCMake/VS10Project/VsControlFlowGuardLinkSetting-check.cmake [deleted file]
Tests/RunCMake/VS10Project/VsControlFlowGuardLinkSetting.cmake [deleted file]
Tests/RunCMake/VS10Project/VsDpiAwareBadParam-stderr.txt
Tests/RunCMake/VS10Project/VsSettings-check.cmake
Tests/RunCMake/VS10Project/VsSettings.cmake
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOff.cmake
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir-build-check.cmake
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir.cmake
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir-build-check.cmake
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir.cmake
Tests/RunCMake/XcodeProject-Embed/ExternalDependencies.cmake [moved from Tests/RunCMake/XcodeProject-Embed/ExternalFramework.cmake with 72% similarity]
Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake
Tests/RunCMake/add_subdirectory/CMP0082-OLD-stderr.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/000-FirstFallbackScript.cmake [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/999-LastFallbackScript.cmake [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/BadArg1-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/BadArg1-stderr.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/BadArg1.cmake [moved from Tests/CMakeTests/CMakeHostSystemInformation-BadArg1.cmake with 100% similarity]
Tests/RunCMake/cmake_host_system_information/BadArg2-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/BadArg2-stderr.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/BadArg2.cmake [moved from Tests/CMakeTests/CMakeHostSystemInformation-BadArg2.cmake with 100% similarity]
Tests/RunCMake/cmake_host_system_information/BadArg3-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/BadArg3-stderr.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/BadArg3.cmake [moved from Tests/CMakeTests/CMakeHostSystemInformation-BadArg3.cmake with 100% similarity]
Tests/RunCMake/cmake_host_system_information/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/CentOS6-stdout.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/CentOS6.cmake [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/CentOS6/etc/centos-release [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/Debian6-stdout.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/Debian6.cmake [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/Debian6/etc/debian_version [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/Exherbo-stdout.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/Exherbo.cmake [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/Exherbo/etc/os-release [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/QueryKeys-stdout.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/QueryKeys.cmake [moved from Tests/CMakeTests/CMakeHostSystemInformationTest.cmake.in with 58% similarity]
Tests/RunCMake/cmake_host_system_information/QueryList-stdout.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/QueryList.cmake [moved from Tests/CMakeTests/CMakeHostSystemInformation-QueryList.cmake with 77% similarity]
Tests/RunCMake/cmake_host_system_information/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/Ubuntu-stdout.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/Ubuntu.cmake [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/Ubuntu/etc/os-release [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/UnitTest-stdout.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/UnitTest.cmake [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/UnitTest/etc/os-release [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/UserFallbackScript-stderr.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/UserFallbackScript-stdout.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/UserFallbackScript.cmake [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/VsMSBuild.cmake [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/VsMSBuildMissing-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/VsMSBuildMissing-stderr.txt [new file with mode: 0644]
Tests/RunCMake/cmake_host_system_information/VsMSBuildMissing.cmake [new file with mode: 0644]
Tests/RunCMake/ctest_environment/CMakeLists.txt.in [new file with mode: 0644]
Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-invalid-op-result.txt [new file with mode: 0644]
Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-invalid-op-stderr.txt [new file with mode: 0644]
Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-invalid-op.cmake [new file with mode: 0644]
Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-colon-result.txt [new file with mode: 0644]
Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-colon-stderr.txt [new file with mode: 0644]
Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-colon.cmake [new file with mode: 0644]
Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-equals-result.txt [new file with mode: 0644]
Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-equals-stderr.txt [new file with mode: 0644]
Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-equals.cmake [new file with mode: 0644]
Tests/RunCMake/ctest_environment/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/ctest_environment/test.cmake.in [new file with mode: 0644]
Tests/RunCMake/ctest_memcheck/ExpectedOutputs-check.cmake [new file with mode: 0644]
Tests/RunCMake/ctest_memcheck/ExpectedOutputs-stderr.txt [new file with mode: 0644]
Tests/RunCMake/ctest_memcheck/ExpectedOutputs-stdout.txt [new file with mode: 0644]
Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake
Tests/RunCMake/ctest_test/RunCMakeTest.cmake
Tests/RunCMake/ctest_test/TestExtraLabels-check.cmake [new file with mode: 0644]
Tests/RunCMake/ctest_test/TestMeasurements-check.cmake
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-notfile-all-stderr.txt
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-unresolved-all-stderr.txt
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-unresolved-all-stderr.txt
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-unresolved-all-stderr.txt
Tests/RunCMake/file-RPATH/RunCMakeTest.cmake
Tests/RunCMake/file/RunCMakeTest.cmake
Tests/RunCMake/find_library/FromScriptMode-stderr-darwin.txt [new file with mode: 0644]
Tests/RunCMake/find_library/FromScriptMode-stderr-windows.txt [new file with mode: 0644]
Tests/RunCMake/find_library/FromScriptMode-stderr.txt [new file with mode: 0644]
Tests/RunCMake/find_library/FromScriptMode.cmake [new file with mode: 0644]
Tests/RunCMake/find_library/RunCMakeTest.cmake
Tests/RunCMake/find_package/CMP0084-OLD-stderr.txt [new file with mode: 0644]
Tests/RunCMake/find_package/MissingNormalForceRequired-result.txt [new file with mode: 0644]
Tests/RunCMake/find_package/MissingNormalForceRequired-stderr.txt [new file with mode: 0644]
Tests/RunCMake/find_package/MissingNormalForceRequired.cmake [new file with mode: 0644]
Tests/RunCMake/find_package/RequiredOptionValuesClash-result.txt [new file with mode: 0644]
Tests/RunCMake/find_package/RequiredOptionValuesClash-stderr.txt [new file with mode: 0644]
Tests/RunCMake/find_package/RequiredOptionValuesClash.cmake [new file with mode: 0644]
Tests/RunCMake/find_package/RunCMakeTest.cmake
Tests/RunCMake/if/IncompleteMatches-stdout.txt [new file with mode: 0644]
Tests/RunCMake/if/IncompleteMatches.cmake [new file with mode: 0644]
Tests/RunCMake/if/IncompleteMatchesFail-result.txt [new file with mode: 0644]
Tests/RunCMake/if/IncompleteMatchesFail-stderr.txt [new file with mode: 0644]
Tests/RunCMake/if/IncompleteMatchesFail.cmake [new file with mode: 0644]
Tests/RunCMake/if/RunCMakeTest.cmake
Tests/RunCMake/if/unbalanced-parenthesis-result.txt [new file with mode: 0644]
Tests/RunCMake/if/unbalanced-parenthesis-stderr.txt [new file with mode: 0644]
Tests/RunCMake/if/unbalanced-parenthesis.cmake [new file with mode: 0644]
Tests/RunCMake/install/CMP0087-OLD-stderr.txt [new file with mode: 0644]
Tests/RunCMake/string/Timestamp-stderr.txt
Tests/RunCMake/string/Timestamp.cmake
Tests/RunCMake/target_compile_features/cxx_not_enabled-stderr.txt
Tests/RunCMake/while/RunCMakeTest.cmake
Tests/RunCMake/while/unbalanced-parenthesis-result.txt [new file with mode: 0644]
Tests/RunCMake/while/unbalanced-parenthesis-stderr.txt [new file with mode: 0644]
Tests/RunCMake/while/unbalanced-parenthesis.cmake [new file with mode: 0644]
Tests/UseSWIG/CMakeLists.txt
Utilities/Doxygen/CMakeLists.txt
Utilities/IWYU/mapping.imp
Utilities/KWIML/include/kwiml/int.h
Utilities/Release/win/x86/Dockerfile
Utilities/Scripts/update-curl.bash
Utilities/Scripts/update-elf.bash [new file with mode: 0755]
Utilities/Scripts/update-jsoncpp.bash
Utilities/Scripts/update-libarchive.bash
Utilities/Scripts/update-third-party.bash
Utilities/Scripts/update-zstd.bash
Utilities/Sphinx/CMakeLists.txt
Utilities/cmThirdPartyChecks.cmake
Utilities/cmcurl/CMake/CurlTests.c
Utilities/cmcurl/CMake/OtherTests.cmake
Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
Utilities/cmcurl/CMakeLists.txt
Utilities/cmcurl/include/curl/curl.h
Utilities/cmcurl/include/curl/curlver.h
Utilities/cmcurl/include/curl/urlapi.h
Utilities/cmcurl/lib/altsvc.c
Utilities/cmcurl/lib/asyn-ares.c
Utilities/cmcurl/lib/asyn-thread.c
Utilities/cmcurl/lib/c-hyper.c
Utilities/cmcurl/lib/c-hyper.h
Utilities/cmcurl/lib/conncache.c
Utilities/cmcurl/lib/connect.c
Utilities/cmcurl/lib/cookie.c
Utilities/cmcurl/lib/cookie.h
Utilities/cmcurl/lib/curl_addrinfo.c
Utilities/cmcurl/lib/curl_config.h.cmake
Utilities/cmcurl/lib/curl_endian.c
Utilities/cmcurl/lib/curl_gssapi.c
Utilities/cmcurl/lib/curl_multibyte.c
Utilities/cmcurl/lib/curl_ntlm_core.c
Utilities/cmcurl/lib/curl_ntlm_wb.c
Utilities/cmcurl/lib/curl_range.c
Utilities/cmcurl/lib/curl_sasl.c
Utilities/cmcurl/lib/curl_setup.h
Utilities/cmcurl/lib/curl_setup_once.h
Utilities/cmcurl/lib/dict.c
Utilities/cmcurl/lib/doh.c
Utilities/cmcurl/lib/doh.h
Utilities/cmcurl/lib/easy.c
Utilities/cmcurl/lib/formdata.c
Utilities/cmcurl/lib/ftp.c
Utilities/cmcurl/lib/hostasyn.c
Utilities/cmcurl/lib/hostcheck.c
Utilities/cmcurl/lib/hostip.c
Utilities/cmcurl/lib/hostip.h
Utilities/cmcurl/lib/hostip4.c
Utilities/cmcurl/lib/hostip6.c
Utilities/cmcurl/lib/hostsyn.c
Utilities/cmcurl/lib/hsts.c
Utilities/cmcurl/lib/hsts.h
Utilities/cmcurl/lib/http.c
Utilities/cmcurl/lib/http.h
Utilities/cmcurl/lib/http2.c
Utilities/cmcurl/lib/http2.h
Utilities/cmcurl/lib/http_aws_sigv4.c
Utilities/cmcurl/lib/http_digest.c
Utilities/cmcurl/lib/http_negotiate.c
Utilities/cmcurl/lib/http_ntlm.c
Utilities/cmcurl/lib/http_proxy.c
Utilities/cmcurl/lib/http_proxy.h
Utilities/cmcurl/lib/imap.c
Utilities/cmcurl/lib/inet_ntop.c
Utilities/cmcurl/lib/krb5.c
Utilities/cmcurl/lib/ldap.c
Utilities/cmcurl/lib/md4.c
Utilities/cmcurl/lib/md5.c
Utilities/cmcurl/lib/mprintf.c
Utilities/cmcurl/lib/mqtt.c
Utilities/cmcurl/lib/multi.c
Utilities/cmcurl/lib/multihandle.h
Utilities/cmcurl/lib/netrc.c
Utilities/cmcurl/lib/non-ascii.c
Utilities/cmcurl/lib/openldap.c
Utilities/cmcurl/lib/pingpong.c
Utilities/cmcurl/lib/pop3.c
Utilities/cmcurl/lib/progress.c
Utilities/cmcurl/lib/quic.h
Utilities/cmcurl/lib/rand.c
Utilities/cmcurl/lib/rtsp.c
Utilities/cmcurl/lib/rtsp.h
Utilities/cmcurl/lib/select.h
Utilities/cmcurl/lib/sendf.c
Utilities/cmcurl/lib/setopt.c
Utilities/cmcurl/lib/sha256.c
Utilities/cmcurl/lib/smb.c
Utilities/cmcurl/lib/smtp.c
Utilities/cmcurl/lib/socketpair.c
Utilities/cmcurl/lib/socks.c
Utilities/cmcurl/lib/socks_gssapi.c
Utilities/cmcurl/lib/socks_sspi.c
Utilities/cmcurl/lib/strdup.c
Utilities/cmcurl/lib/strdup.h
Utilities/cmcurl/lib/strerror.c
Utilities/cmcurl/lib/telnet.c
Utilities/cmcurl/lib/tftp.c
Utilities/cmcurl/lib/transfer.c
Utilities/cmcurl/lib/url.c
Utilities/cmcurl/lib/urlapi.c
Utilities/cmcurl/lib/urldata.h
Utilities/cmcurl/lib/vauth/digest_sspi.c
Utilities/cmcurl/lib/vauth/krb5_gssapi.c
Utilities/cmcurl/lib/vauth/krb5_sspi.c
Utilities/cmcurl/lib/vauth/ntlm.c
Utilities/cmcurl/lib/vauth/ntlm_sspi.c
Utilities/cmcurl/lib/vauth/spnego_gssapi.c
Utilities/cmcurl/lib/vauth/spnego_sspi.c
Utilities/cmcurl/lib/vauth/vauth.h
Utilities/cmcurl/lib/version.c
Utilities/cmcurl/lib/vquic/ngtcp2.c
Utilities/cmcurl/lib/vquic/ngtcp2.h
Utilities/cmcurl/lib/vquic/quiche.c
Utilities/cmcurl/lib/vssh/libssh.c
Utilities/cmcurl/lib/vssh/libssh2.c
Utilities/cmcurl/lib/vssh/ssh.h
Utilities/cmcurl/lib/vssh/wolfssh.c
Utilities/cmcurl/lib/vtls/bearssl.c
Utilities/cmcurl/lib/vtls/gskit.c
Utilities/cmcurl/lib/vtls/gtls.c
Utilities/cmcurl/lib/vtls/mbedtls.c
Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
Utilities/cmcurl/lib/vtls/mesalink.c
Utilities/cmcurl/lib/vtls/nss.c
Utilities/cmcurl/lib/vtls/openssl.c
Utilities/cmcurl/lib/vtls/rustls.c
Utilities/cmcurl/lib/vtls/schannel.c
Utilities/cmcurl/lib/vtls/schannel_verify.c
Utilities/cmcurl/lib/vtls/sectransp.c
Utilities/cmcurl/lib/vtls/vtls.c
Utilities/cmcurl/lib/vtls/vtls.h
Utilities/cmcurl/lib/vtls/wolfssl.c
Utilities/cmcurl/lib/warnless.c
Utilities/cmcurl/lib/x509asn1.c
Utilities/cmcurl/lib/x509asn1.h
Utilities/cmelf/elf32.h [new file with mode: 0644]
Utilities/cmelf/elf64.h [new file with mode: 0644]
Utilities/cmelf/elf_common.h [new file with mode: 0644]
Utilities/cmjsoncpp/include/json/allocator.h
Utilities/cmjsoncpp/include/json/assertions.h
Utilities/cmjsoncpp/include/json/config.h
Utilities/cmjsoncpp/include/json/forwards.h
Utilities/cmjsoncpp/include/json/json.h
Utilities/cmjsoncpp/include/json/json_features.h [moved from Utilities/cmjsoncpp/include/json/features.h with 87% similarity]
Utilities/cmjsoncpp/include/json/reader.h
Utilities/cmjsoncpp/include/json/value.h
Utilities/cmjsoncpp/include/json/version.h
Utilities/cmjsoncpp/include/json/writer.h
Utilities/cmjsoncpp/src/lib_json/json_reader.cpp
Utilities/cmjsoncpp/src/lib_json/json_tool.h
Utilities/cmjsoncpp/src/lib_json/json_value.cpp
Utilities/cmjsoncpp/src/lib_json/json_valueiterator.inl
Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
Utilities/cmlibarchive/CMakeLists.txt
Utilities/cmlibarchive/COPYING
Utilities/cmlibarchive/build/cmake/CreatePkgConfigFile.cmake
Utilities/cmlibarchive/build/cmake/config.h.in
Utilities/cmlibarchive/build/version
Utilities/cmlibarchive/libarchive/archive.h
Utilities/cmlibarchive/libarchive/archive_acl.c
Utilities/cmlibarchive/libarchive/archive_check_magic.c
Utilities/cmlibarchive/libarchive/archive_cryptor.c
Utilities/cmlibarchive/libarchive/archive_cryptor_private.h
Utilities/cmlibarchive/libarchive/archive_digest.c
Utilities/cmlibarchive/libarchive/archive_digest_private.h
Utilities/cmlibarchive/libarchive/archive_entry.c
Utilities/cmlibarchive/libarchive/archive_entry.h
Utilities/cmlibarchive/libarchive/archive_entry_private.h
Utilities/cmlibarchive/libarchive/archive_entry_stat.3
Utilities/cmlibarchive/libarchive/archive_ppmd7.c
Utilities/cmlibarchive/libarchive/archive_read.c
Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.c
Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c
Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
Utilities/cmlibarchive/libarchive/archive_read_filter.3
Utilities/cmlibarchive/libarchive/archive_read_open_filename.c
Utilities/cmlibarchive/libarchive/archive_read_set_format.c
Utilities/cmlibarchive/libarchive/archive_read_support_filter_by_code.c [new file with mode: 0644]
Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c
Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_by_code.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_empty.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_rar5.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_warc.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
Utilities/cmlibarchive/libarchive/archive_string.c
Utilities/cmlibarchive/libarchive/archive_string.h
Utilities/cmlibarchive/libarchive/archive_util.c
Utilities/cmlibarchive/libarchive/archive_write.c
Utilities/cmlibarchive/libarchive/archive_write_add_filter_program.c
Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c
Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c
Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c
Utilities/cmlibarchive/libarchive/archive_write_open.3
Utilities/cmlibarchive/libarchive/archive_write_open_fd.c
Utilities/cmlibarchive/libarchive/archive_write_open_file.c
Utilities/cmlibarchive/libarchive/archive_write_open_filename.c
Utilities/cmlibarchive/libarchive/archive_write_open_memory.c
Utilities/cmlibarchive/libarchive/archive_write_private.h
Utilities/cmlibarchive/libarchive/archive_write_set_format.c
Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c
Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_newc.c
Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c
Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c
Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c
Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c
Utilities/cmlibarchive/libarchive/archive_write_set_options.3
Utilities/cmlibarchive/libarchive/config_freebsd.h
Utilities/cmlibarchive/libarchive/cpio.5
Utilities/cmlibarchive/libarchive/filter_fork.h
Utilities/cmlibarchive/libarchive/filter_fork_posix.c
Utilities/cmlibarchive/libarchive/filter_fork_windows.c
Utilities/cmlibuv/include/uv/win.h
Utilities/cmlibuv/src/unix/core.c
Utilities/cmlibuv/src/win/process.c
Utilities/cmzstd/README.md
Utilities/cmzstd/lib/common/bitstream.h
Utilities/cmzstd/lib/common/compiler.h
Utilities/cmzstd/lib/common/cpu.h
Utilities/cmzstd/lib/common/debug.c
Utilities/cmzstd/lib/common/debug.h
Utilities/cmzstd/lib/common/entropy_common.c
Utilities/cmzstd/lib/common/error_private.c
Utilities/cmzstd/lib/common/error_private.h
Utilities/cmzstd/lib/common/fse.h
Utilities/cmzstd/lib/common/fse_decompress.c
Utilities/cmzstd/lib/common/huf.h
Utilities/cmzstd/lib/common/mem.h
Utilities/cmzstd/lib/common/pool.c
Utilities/cmzstd/lib/common/pool.h
Utilities/cmzstd/lib/common/threading.c
Utilities/cmzstd/lib/common/xxhash.c
Utilities/cmzstd/lib/common/xxhash.h
Utilities/cmzstd/lib/common/zstd_common.c
Utilities/cmzstd/lib/common/zstd_deps.h [new file with mode: 0644]
Utilities/cmzstd/lib/common/zstd_internal.h
Utilities/cmzstd/lib/common/zstd_trace.h [new file with mode: 0644]
Utilities/cmzstd/lib/compress/fse_compress.c
Utilities/cmzstd/lib/compress/hist.c
Utilities/cmzstd/lib/compress/hist.h
Utilities/cmzstd/lib/compress/huf_compress.c
Utilities/cmzstd/lib/compress/zstd_compress.c
Utilities/cmzstd/lib/compress/zstd_compress_internal.h
Utilities/cmzstd/lib/compress/zstd_compress_literals.c
Utilities/cmzstd/lib/compress/zstd_compress_literals.h
Utilities/cmzstd/lib/compress/zstd_compress_sequences.c
Utilities/cmzstd/lib/compress/zstd_compress_sequences.h
Utilities/cmzstd/lib/compress/zstd_compress_superblock.c
Utilities/cmzstd/lib/compress/zstd_compress_superblock.h
Utilities/cmzstd/lib/compress/zstd_cwksp.h
Utilities/cmzstd/lib/compress/zstd_double_fast.c
Utilities/cmzstd/lib/compress/zstd_double_fast.h
Utilities/cmzstd/lib/compress/zstd_fast.c
Utilities/cmzstd/lib/compress/zstd_fast.h
Utilities/cmzstd/lib/compress/zstd_lazy.c
Utilities/cmzstd/lib/compress/zstd_lazy.h
Utilities/cmzstd/lib/compress/zstd_ldm.c
Utilities/cmzstd/lib/compress/zstd_ldm.h
Utilities/cmzstd/lib/compress/zstd_ldm_geartab.h [new file with mode: 0644]
Utilities/cmzstd/lib/compress/zstd_opt.c
Utilities/cmzstd/lib/compress/zstd_opt.h
Utilities/cmzstd/lib/compress/zstdmt_compress.c
Utilities/cmzstd/lib/compress/zstdmt_compress.h
Utilities/cmzstd/lib/decompress/huf_decompress.c
Utilities/cmzstd/lib/decompress/zstd_ddict.c
Utilities/cmzstd/lib/decompress/zstd_ddict.h
Utilities/cmzstd/lib/decompress/zstd_decompress.c
Utilities/cmzstd/lib/decompress/zstd_decompress_block.c
Utilities/cmzstd/lib/decompress/zstd_decompress_block.h
Utilities/cmzstd/lib/decompress/zstd_decompress_internal.h
Utilities/cmzstd/lib/deprecated/zbuff.h
Utilities/cmzstd/lib/deprecated/zbuff_common.c
Utilities/cmzstd/lib/deprecated/zbuff_compress.c
Utilities/cmzstd/lib/deprecated/zbuff_decompress.c
Utilities/cmzstd/lib/dictBuilder/cover.c
Utilities/cmzstd/lib/dictBuilder/cover.h
Utilities/cmzstd/lib/dictBuilder/divsufsort.c
Utilities/cmzstd/lib/dictBuilder/fastcover.c
Utilities/cmzstd/lib/dictBuilder/zdict.c
Utilities/cmzstd/lib/zdict.h [moved from Utilities/cmzstd/lib/dictBuilder/zdict.h with 70% similarity]
Utilities/cmzstd/lib/zstd.h
Utilities/cmzstd/lib/zstd_errors.h [moved from Utilities/cmzstd/lib/common/zstd_errors.h with 97% similarity]
bootstrap

index d2a04fe..7a3e4ed 100644 (file)
@@ -160,6 +160,7 @@ syn keyword cmakeProperty contained
             \ ENABLED_LANGUAGES
             \ ENABLE_EXPORTS
             \ ENVIRONMENT
+            \ ENVIRONMENT_MODIFICATION
             \ EXCLUDE_FROM_ALL
             \ EXCLUDE_FROM_DEFAULT_BUILD
             \ EXPORT_NAME
@@ -2807,6 +2808,7 @@ syn keyword cmakeKWfind_package contained
             \ ABI
             \ BUNDLE
             \ CMAKE_DISABLE_FIND_PACKAGE_
+            \ CMAKE_REQUIRE_FIND_PACKAGE_
             \ CMAKE_FIND_ROOT_PATH_BOTH
             \ COMPONENTS
             \ CONFIG
index 9944ea4..fdfe456 100644 (file)
@@ -1,7 +1,7 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-cmake_minimum_required(VERSION 3.1...3.19 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.1...3.20 FATAL_ERROR)
 set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake)
 set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake)
 project(CMake)
@@ -815,8 +815,12 @@ CMAKE_SETUP_TESTING()
 
 if(NOT CMake_TEST_EXTERNAL_CMAKE)
   if(NOT CMake_VERSION_IS_RELEASE)
-    if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND
-        NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS 4.2)
+    if((CMAKE_C_COMPILER_ID STREQUAL "GNU" AND
+        NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS 4.2) OR
+       (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND
+        NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS 3.0 AND
+        NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC") OR
+       CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
       set(C_FLAGS_LIST -Wcast-align -Werror-implicit-function-declaration -Wchar-subscripts
                        -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security
                        -Wmissing-format-attribute -fno-common -Wundef
index 2b902a9..998e146 100644 (file)
@@ -13,46 +13,236 @@ queried.  The list of queried values is stored in ``<variable>``.
 
 ``<key>`` can be one of the following values:
 
-============================= ================================================
-Key                           Description
-============================= ================================================
-``NUMBER_OF_LOGICAL_CORES``   Number of logical cores
-``NUMBER_OF_PHYSICAL_CORES``  Number of physical cores
-``HOSTNAME``                  Hostname
-``FQDN``                      Fully qualified domain name
-``TOTAL_VIRTUAL_MEMORY``      Total virtual memory in MiB [#mebibytes]_
-``AVAILABLE_VIRTUAL_MEMORY``  Available virtual memory in MiB [#mebibytes]_
-``TOTAL_PHYSICAL_MEMORY``     Total physical memory in MiB [#mebibytes]_
-``AVAILABLE_PHYSICAL_MEMORY`` Available physical memory in MiB [#mebibytes]_
-============================= ================================================
-
-.. versionadded:: 3.10
-  Additional ``<key>`` values are available:
-
-============================= ================================================
-Key                           Description
-============================= ================================================
-``IS_64BIT``                  One if processor is 64Bit
-``HAS_FPU``                   One if processor has floating point unit
-``HAS_MMX``                   One if processor supports MMX instructions
-``HAS_MMX_PLUS``              One if processor supports Ext. MMX instructions
-``HAS_SSE``                   One if processor supports SSE instructions
-``HAS_SSE2``                  One if processor supports SSE2 instructions
-``HAS_SSE_FP``                One if processor supports SSE FP instructions
-``HAS_SSE_MMX``               One if processor supports SSE MMX instructions
-``HAS_AMD_3DNOW``             One if processor supports 3DNow instructions
-``HAS_AMD_3DNOW_PLUS``        One if processor supports 3DNow+ instructions
-``HAS_IA64``                  One if IA64 processor emulating x86
-``HAS_SERIAL_NUMBER``         One if processor has serial number
-``PROCESSOR_SERIAL_NUMBER``   Processor serial number
-``PROCESSOR_NAME``            Human readable processor name
-``PROCESSOR_DESCRIPTION``     Human readable full processor description
-``OS_NAME``                   See :variable:`CMAKE_HOST_SYSTEM_NAME`
-``OS_RELEASE``                The OS sub-type e.g. on Windows ``Professional``
-``OS_VERSION``                The OS build ID
-``OS_PLATFORM``               See :variable:`CMAKE_HOST_SYSTEM_PROCESSOR`
-============================= ================================================
+``NUMBER_OF_LOGICAL_CORES``
+  Number of logical cores
+
+``NUMBER_OF_PHYSICAL_CORES``
+  Number of physical cores
+
+``HOSTNAME``
+  Hostname
+
+``FQDN``
+  Fully qualified domain name
+
+``TOTAL_VIRTUAL_MEMORY``
+  Total virtual memory in MiB [#mebibytes]_
+
+``AVAILABLE_VIRTUAL_MEMORY``
+  Available virtual memory in MiB [#mebibytes]_
+
+``TOTAL_PHYSICAL_MEMORY``
+  Total physical memory in MiB [#mebibytes]_
+
+``AVAILABLE_PHYSICAL_MEMORY``
+  Available physical memory in MiB [#mebibytes]_
+
+``IS_64BIT``
+  .. versionadded:: 3.10
+
+  One if processor is 64Bit
+
+``HAS_FPU``
+  .. versionadded:: 3.10
+
+  One if processor has floating point unit
+
+``HAS_MMX``
+  .. versionadded:: 3.10
+
+  One if processor supports MMX instructions
+
+``HAS_MMX_PLUS``
+  .. versionadded:: 3.10
+
+  One if processor supports Ext. MMX instructions
+
+``HAS_SSE``
+  .. versionadded:: 3.10
+
+  One if processor supports SSE instructions
+
+``HAS_SSE2``
+  .. versionadded:: 3.10
+
+  One if processor supports SSE2 instructions
+
+``HAS_SSE_FP``
+  .. versionadded:: 3.10
+
+  One if processor supports SSE FP instructions
+
+``HAS_SSE_MMX``
+  .. versionadded:: 3.10
+
+  One if processor supports SSE MMX instructions
+
+``HAS_AMD_3DNOW``
+  .. versionadded:: 3.10
+
+  One if processor supports 3DNow instructions
+
+``HAS_AMD_3DNOW_PLUS``
+  .. versionadded:: 3.10
+
+  One if processor supports 3DNow+ instructions
+
+``HAS_IA64``
+  .. versionadded:: 3.10
+
+  One if IA64 processor emulating x86
+
+``HAS_SERIAL_NUMBER``
+  .. versionadded:: 3.10
+
+  One if processor has serial number
+
+``PROCESSOR_SERIAL_NUMBER``
+  .. versionadded:: 3.10
+
+  Processor serial number
+
+``PROCESSOR_NAME``
+  .. versionadded:: 3.10
+
+  Human readable processor name
+
+``PROCESSOR_DESCRIPTION``
+  .. versionadded:: 3.10
+
+  Human readable full processor description
+
+``OS_NAME``
+  .. versionadded:: 3.10
+
+  See :variable:`CMAKE_HOST_SYSTEM_NAME`
+
+``OS_RELEASE``
+  .. versionadded:: 3.10
+
+  The OS sub-type e.g. on Windows ``Professional``
+
+``OS_VERSION``
+  .. versionadded:: 3.10
+
+  The OS build ID
+
+``OS_PLATFORM``
+  .. versionadded:: 3.10
+
+  See :variable:`CMAKE_HOST_SYSTEM_PROCESSOR`
+
+``DISTRIB_INFO``
+  .. versionadded:: 3.22
+
+  Read :file:`/etc/os-release` file and define the given ``<variable>``
+  into a list of read variables
+
+``DISTRIB_<name>``
+  .. versionadded:: 3.22
+
+  Get the ``<name>`` variable (see `man 5 os-release`_) if it exists in the
+  :file:`/etc/os-release` file
+
+  Example:
+
+  .. code-block:: cmake
+
+      cmake_host_system_information(RESULT PRETTY_NAME QUERY DISTRIB_PRETTY_NAME)
+      message(STATUS "${PRETTY_NAME}")
+
+      cmake_host_system_information(RESULT DISTRO QUERY DISTRIB_INFO)
+
+      foreach(VAR IN LISTS DISTRO)
+        message(STATUS "${VAR}=`${${VAR}}`")
+      endforeach()
+
+
+  Output::
+
+    -- Ubuntu 20.04.2 LTS
+    -- DISTRO_BUG_REPORT_URL=`https://bugs.launchpad.net/ubuntu/`
+    -- DISTRO_HOME_URL=`https://www.ubuntu.com/`
+    -- DISTRO_ID=`ubuntu`
+    -- DISTRO_ID_LIKE=`debian`
+    -- DISTRO_NAME=`Ubuntu`
+    -- DISTRO_PRETTY_NAME=`Ubuntu 20.04.2 LTS`
+    -- DISTRO_PRIVACY_POLICY_URL=`https://www.ubuntu.com/legal/terms-and-policies/privacy-policy`
+    -- DISTRO_SUPPORT_URL=`https://help.ubuntu.com/`
+    -- DISTRO_UBUNTU_CODENAME=`focal`
+    -- DISTRO_VERSION=`20.04.2 LTS (Focal Fossa)`
+    -- DISTRO_VERSION_CODENAME=`focal`
+    -- DISTRO_VERSION_ID=`20.04`
+
+If :file:`/etc/os-release` file is not found, the command tries to gather OS
+identification via fallback scripts.  The fallback script can use `various
+distribution-specific files`_ to collect OS identification data and map it
+into `man 5 os-release`_ variables.
+
+Fallback Interface Variables
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. variable:: CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTS
+
+  In addition to the scripts shipped with CMake, a user may append full
+  paths to his script(s) to the this list.  The script filename has the
+  following format: ``NNN-<name>.cmake``, where ``NNN`` is three digits
+  used to apply collected scripts in a specific order.
+
+.. variable:: CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_<varname>
+
+  Variables collected by the user provided fallback script
+  ought to be assigned to CMake variables using this naming
+  convention.  Example, the ``ID`` variable from the manual becomes
+  ``CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID``.
+
+.. variable:: CMAKE_GET_OS_RELEASE_FALLBACK_RESULT
+
+  The fallback script ought to store names of all assigned
+  ``CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_<varname>`` variables in this list.
+
+Example:
+
+.. code-block:: cmake
+
+  # Try to detect some old distribution
+  # See also
+  # - http://linuxmafia.com/faq/Admin/release-files.html
+  #
+  if(NOT EXISTS "${CMAKE_SYSROOT}/etc/foobar-release")
+    return()
+  endif()
+  # Get the first string only
+  file(
+      STRINGS "${CMAKE_SYSROOT}/etc/foobar-release" CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT
+      LIMIT_COUNT 1
+    )
+  #
+  # Example:
+  #
+  #   Foobar distribution release 1.2.3 (server)
+  #
+  if(CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT MATCHES "Foobar distribution release ([0-9\.]+) .*")
+    set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_NAME Foobar)
+    set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_PRETTY_NAME "${CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT}")
+    set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID foobar)
+    set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION ${CMAKE_MATCH_1})
+    set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION_ID ${CMAKE_MATCH_1})
+    list(
+        APPEND CMAKE_GET_OS_RELEASE_FALLBACK_RESULT
+        CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_NAME
+        CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_PRETTY_NAME
+        CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID
+        CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION
+        CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION_ID
+      )
+  endif()
+  unset(CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT)
+
 
 .. rubric:: Footnotes
 
 .. [#mebibytes] One MiB (mebibyte) is equal to 1024x1024 bytes.
+
+.. _man 5 os-release: https://www.freedesktop.org/software/systemd/man/os-release.html
+.. _various distribution-specific files: http://linuxmafia.com/faq/Admin/release-files.html
index 086668c..1d81423 100644 (file)
@@ -96,6 +96,7 @@ The arguments are:
   with respect to the value of :variable:`CMAKE_CURRENT_BINARY_DIR`.
   If the path names an existing directory the output file is placed
   in that directory with the same file name as the input file.
+  If the path contains non-existent directories, they are created.
 
 ``NO_SOURCE_PERMISSIONS``
   .. versionadded:: 3.19
index e6d277f..d661825 100644 (file)
@@ -30,7 +30,8 @@ The options are:
     Build      = ctest_build results, in Build.xml
     Test       = ctest_test results, in Test.xml
     Coverage   = ctest_coverage results, in Coverage.xml
-    MemCheck   = ctest_memcheck results, in DynamicAnalysis.xml
+    MemCheck   = ctest_memcheck results, in DynamicAnalysis.xml and
+                 DynamicAnalysis-Test.xml
     Notes      = Files listed by CTEST_NOTES_FILES, in Notes.xml
     ExtraFiles = Files listed by CTEST_EXTRA_SUBMIT_FILES
     Upload     = Files prepared for upload by ctest_upload(), in Upload.xml
index 89787d1..6a9a6a0 100644 (file)
@@ -190,29 +190,34 @@ Check the `CDash test measurement documentation
 <https://github.com/Kitware/CDash/blob/master/docs/test_measurements.md>`_
 for more information on the types of test measurements that CDash recognizes.
 
+.. versionadded: 3.22
+  CTest can parse custom measurements from tags named
+  ``<CTestMeasurement>`` or ``<CTestMeasurementFile>``. The older names
+  ``<DartMeasurement>`` and ``<DartMeasurementFile>`` are still supported.
+
 The following example demonstrates how to output a variety of custom test
 measurements.
 
 .. code-block:: c++
 
    std::cout <<
-     "<DartMeasurement type=\"numeric/double\" name=\"score\">28.3</DartMeasurement>"
+     "<CTestMeasurement type=\"numeric/double\" name=\"score\">28.3</CTestMeasurement>"
      << std::endl;
 
    std::cout <<
-     "<DartMeasurement type=\"text/string\" name=\"color\">red</DartMeasurement>"
+     "<CTestMeasurement type=\"text/string\" name=\"color\">red</CTestMeasurement>"
      << std::endl;
 
    std::cout <<
-     "<DartMeasurement type=\"text/link\" name=\"CMake URL\">https://cmake.org</DartMeasurement>"
+     "<CTestMeasurement type=\"text/link\" name=\"CMake URL\">https://cmake.org</CTestMeasurement>"
      << std::endl;
 
    std::cout <<
-     "<DartMeasurement type=\"text/preformatted\" name=\"Console Output\">" <<
+     "<CTestMeasurement type=\"text/preformatted\" name=\"Console Output\">" <<
      "line 1.\n" <<
      "  \033[31;1m line 2. Bold red, and indented!\033[0;0ml\n" <<
      "line 3. Not bold or indented...\n" <<
-     "</DartMeasurement>" << std::endl;
+     "</CTestMeasurement>" << std::endl;
 
 Image Measurements
 """"""""""""""""""
@@ -222,16 +227,16 @@ The following example demonstrates how to upload test images to CDash.
 .. code-block:: c++
 
    std::cout <<
-     "<DartMeasurementFile type=\"image/jpg\" name=\"TestImage\">" <<
-     "/dir/to/test_img.jpg</DartMeasurementFile>" << std::endl;
+     "<CTestMeasurementFile type=\"image/jpg\" name=\"TestImage\">" <<
+     "/dir/to/test_img.jpg</CTestMeasurementFile>" << std::endl;
 
    std::cout <<
-     "<DartMeasurementFile type=\"image/gif\" name=\"ValidImage\">" <<
-     "/dir/to/valid_img.gif</DartMeasurementFile>" << std::endl;
+     "<CTestMeasurementFile type=\"image/gif\" name=\"ValidImage\">" <<
+     "/dir/to/valid_img.gif</CTestMeasurementFile>" << std::endl;
 
    std::cout <<
-     "<DartMeasurementFile type=\"image/png\" name=\"AlgoResult\"> <<
-     "/dir/to/img.png</DartMeasurementFile>"
+     "<CTestMeasurementFile type=\"image/png\" name=\"AlgoResult\"> <<
+     "/dir/to/img.png</CTestMeasurementFile>"
      << std::endl;
 
 Images will be displayed together in an interactive comparison mode on CDash
@@ -252,13 +257,17 @@ separate from the interactive comparison UI.
 Attached Files
 """"""""""""""
 
+.. versionadded:: 3.21
+
 The following example demonstrates how to upload non-image files to CDash.
 
 .. code-block:: c++
 
    std::cout <<
-     "<DartMeasurementFile type=\"file\" name=\"MyTestInputData\">" <<
-     "/dir/to/data.csv</DartMeasurementFile>" << std::endl;
+     "<CTestMeasurementFile type=\"file\" name=\"TestInputData1\">" <<
+     "/dir/to/data1.csv</CTestMeasurementFile>\n"                   <<
+     "<CTestMeasurementFile type=\"file\" name=\"TestInputData2\">" <<
+     "/dir/to/data2.csv</CTestMeasurementFile>"                     << std::endl;
 
 If the name of the file to upload is known at configure time, you can use the
 :prop_test:`ATTACHED_FILES` or :prop_test:`ATTACHED_FILES_ON_FAIL` test
@@ -267,6 +276,8 @@ properties instead.
 Custom Details
 """"""""""""""
 
+.. versionadded:: 3.21
+
 The following example demonstrates how to specify a custom value for the
 ``Test Details`` field displayed on CDash.
 
@@ -274,3 +285,22 @@ The following example demonstrates how to specify a custom value for the
 
    std::cout <<
      "<CTestDetails>My Custom Details Value</CTestDetails>" << std::endl;
+
+.. _`Additional Labels`:
+
+Additional Labels
+"""""""""""""""""
+
+.. versionadded:: 3.22
+
+The following example demonstrates how to add additional labels to a test
+at runtime.
+
+.. code-block:: c++
+
+   std::cout <<
+     "<CTestLabel>Custom Label 1</CTestLabel>\n" <<
+     "<CTestLabel>Custom Label 2</CTestLabel>"   << std::endl;
+
+Use the :prop_test:`LABELS` test property instead for labels that can be
+determined at configure time.
index f038871..799b6ff 100644 (file)
@@ -838,11 +838,16 @@ of their content even if options are used to select a subset of
 files.
 
 The ``INSTALL`` signature differs slightly from ``COPY``: it prints
-status messages (subject to the :variable:`CMAKE_INSTALL_MESSAGE` variable),
-and ``NO_SOURCE_PERMISSIONS`` is default.
+status messages, and ``NO_SOURCE_PERMISSIONS`` is default.
+
 Installation scripts generated by the :command:`install` command
 use this signature (with some undocumented options for internal use).
 
+.. versionchanged:: 3.22
+
+  The environment variable :envvar:`CMAKE_INSTALL_MODE` can override the
+  default copying behavior of :command:`file(INSTALL)`.
+
 .. _SIZE:
 
 .. code-block:: cmake
@@ -1068,7 +1073,7 @@ Options to both ``DOWNLOAD`` and ``UPLOAD`` are:
   .. versionadded:: 3.11
 
   Specify whether the .netrc file is to be used for operation.  If this
-  option is not specified, the value of the ``CMAKE_NETRC`` variable
+  option is not specified, the value of the :variable:`CMAKE_NETRC` variable
   will be used instead.
   Valid levels are:
 
@@ -1087,29 +1092,28 @@ Options to both ``DOWNLOAD`` and ``UPLOAD`` are:
 
   Specify an alternative .netrc file to the one in your home directory,
   if the ``NETRC`` level is ``OPTIONAL`` or ``REQUIRED``. If this option
-  is not specified, the value of the ``CMAKE_NETRC_FILE`` variable will
+  is not specified, the value of the :variable:`CMAKE_NETRC_FILE` variable will
   be used instead.
 
-If neither ``NETRC`` option is given CMake will check variables
-``CMAKE_NETRC`` and ``CMAKE_NETRC_FILE``, respectively.
-
 ``TLS_VERIFY <ON|OFF>``
   Specify whether to verify the server certificate for ``https://`` URLs.
-  The default is to *not* verify.
+  The default is to *not* verify. If this option is not specified, the value
+  of the :variable:`CMAKE_TLS_VERIFY` variable will be used instead.
 
   .. versionadded:: 3.18
     Added support to ``file(UPLOAD)``.
 
 ``TLS_CAINFO <file>``
-  Specify a custom Certificate Authority file for ``https://`` URLs.
+  Specify a custom Certificate Authority file for ``https://`` URLs. If this
+  option is not specified, the value of the :variable:`CMAKE_TLS_CAINFO`
+  variable will be used instead.
 
   .. versionadded:: 3.18
     Added support to ``file(UPLOAD)``.
 
 For ``https://`` URLs CMake must be built with OpenSSL support.  ``TLS/SSL``
 certificates are not checked by default.  Set ``TLS_VERIFY`` to ``ON`` to
-check certificates. If neither ``TLS`` option is given CMake will check
-variables :variable:`CMAKE_TLS_VERIFY` and ``CMAKE_TLS_CAINFO``, respectively.
+check certificates.
 
 Additional options to ``DOWNLOAD`` are:
 
index 3dfd62f..1a79a8a 100644 (file)
@@ -5,12 +5,74 @@ find_package
 
    .. contents::
 
-Find an external project, and load its settings.
+Find a package (usually provided by something external to the project),
+and load its package-specific details.
+
+Search Modes
+^^^^^^^^^^^^
+
+The command has two very distinct ways of conducting the search:
+
+**Module mode**
+  In this mode, CMake searches for a file called ``Find<PackageName>.cmake``,
+  looking first in the locations listed in the :variable:`CMAKE_MODULE_PATH`,
+  then among the :ref:`Find Modules` provided by the CMake installation.
+  If the file is found, it is read and processed by CMake.  It is responsible
+  for finding the package, checking the version, and producing any needed
+  messages.  Some Find modules provide limited or no support for versioning;
+  check the Find module's documentation.
+
+  The ``Find<PackageName>.cmake`` file is not typically provided by the
+  package itself.  Rather, it is normally provided by something external to
+  the package, such as the operating system, CMake itself, or even the project
+  from which the ``find_package()`` command was called.  Being externally
+  provided, :ref:`Find Modules` tend to be heuristic in nature and are
+  susceptible to becoming out-of-date.  They typically search for certain
+  libraries, files and other package artifacts.
+
+  Module mode is only supported by the
+  :ref:`basic command signature <Basic Signature>`.
+
+**Config mode**
+  In this mode, CMake searches for a file called
+  ``<lowercasePackageName>-config.cmake`` or ``<PackageName>Config.cmake``.
+  It will also look for ``<lowercasePackageName>-config-version.cmake`` or
+  ``<PackageName>ConfigVersion.cmake`` if version details were specified
+  (see :ref:`version selection` for an explanation of how these separate
+  version files are used).
+
+  In config mode, the command can be given a list of names to search for
+  as package names.  The locations where CMake searches for the config and
+  version files is considerably more complicated than for Module mode
+  (see :ref:`search procedure`).
+
+  The config and version files are typically installed as part of the
+  package, so they tend to be more reliable than Find modules.  They usually
+  contain direct knowledge of the package contents, so no searching or
+  heuristics are needed within the config or version files themselves.
+
+  Config mode is supported by both the :ref:`basic <Basic Signature>` and
+  :ref:`full <Full Signature>` command signatures.
+
+The command arguments determine which of the above modes is used.  When the
+`basic signature`_ is used, the command searches in Module mode first.
+If the package is not found, the search falls back to Config mode.
+A user may set the :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` variable
+to true to reverse the priority and direct CMake to search using Config mode
+first before falling back to Module mode.  The basic signature can also be
+forced to use only Module mode with a ``MODULE`` keyword.  If the
+`full signature`_ is used, the command only searches in Config mode.
+
+Where possible, user code should generally look for packages using the
+`basic signature`_, since that allows the package to be found with either mode.
+Project maintainers wishing to provide a config package should understand
+the bigger picture, as explained in :ref:`Full Signature` and all subsequent
+sections on this page.
 
 .. _`basic signature`:
 
-Basic Signature and Module Mode
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Basic Signature
+^^^^^^^^^^^^^^^
 
 .. code-block:: cmake
 
@@ -19,20 +81,39 @@ Basic Signature and Module Mode
                [OPTIONAL_COMPONENTS components...]
                [NO_POLICY_SCOPE])
 
-Finds and loads settings from an external project.  ``<PackageName>_FOUND``
-will be set to indicate whether the package was found.  When the
-package is found package-specific information is provided through
-variables and :ref:`Imported Targets` documented by the package itself.  The
+The basic signature is supported by both Module and Config modes.
+The ``MODULE`` keyword implies that only Module mode can be used to find
+the package, with no fallback to Config mode.
+
+Regardless of the mode used, a ``<PackageName>_FOUND`` variable will be
+set to indicate whether the package was found.  When the package is found,
+package-specific information may be provided through other variables and
+:ref:`Imported Targets` documented by the package itself.  The
 ``QUIET`` option disables informational messages, including those indicating
 that the package cannot be found if it is not ``REQUIRED``.  The ``REQUIRED``
 option stops processing with an error message if the package cannot be found.
 
 A package-specific list of required components may be listed after the
-``COMPONENTS`` option (or after the ``REQUIRED`` option if present).
+``COMPONENTS`` keyword.  If any of these components are not able to be
+satisfied, the package overall is considered to be not found.  If the
+``REQUIRED`` option is also present, this is treated as a fatal error,
+otherwise execution still continues.  As a form of shorthand, if the
+``REQUIRED`` option is present, the ``COMPONENTS`` keyword can be omitted
+and the required components can be listed directly after ``REQUIRED``.
+
 Additional optional components may be listed after
-``OPTIONAL_COMPONENTS``.  Available components and their influence on
-whether a package is considered to be found are defined by the target
-package.
+``OPTIONAL_COMPONENTS``.  If these cannot be satisfied, the package overall
+can still be considered found, as long as all required components are
+satisfied.
+
+The set of available components and their meaning are defined by the
+target package.  Formally, it is up to the target package how to
+interpret the component information given to it, but it should follow
+the expectations stated above.  For calls where no components are specified,
+there is no single expected behavior and target packages should clearly
+define what occurs in such cases.  Common arrangements include assuming it
+should find all components, no components or some well-defined subset of the
+available components.
 
 .. _FIND_PACKAGE_VERSION_FORMAT:
 
@@ -40,12 +121,13 @@ The ``[version]`` argument requests a version with which the package found
 should be compatible. There are two possible forms in which it may be
 specified:
 
-  * A single version with the format ``major[.minor[.patch[.tweak]]]``.
+  * A single version with the format ``major[.minor[.patch[.tweak]]]``, where
+    each component is a numeric value.
   * A version range with the format ``versionMin...[<]versionMax`` where
-    ``versionMin`` and ``versionMax`` have the same format as the single
-    version.  By default, both end points are included.  By specifying ``<``,
-    the upper end point will be excluded.  Version ranges are only supported
-    with CMake 3.19 or later.
+    ``versionMin`` and ``versionMax`` have the same format and constraints
+    on components being integers as the single version.  By default, both end
+    points are included.  By specifying ``<``, the upper end point will be
+    excluded. Version ranges are only supported with CMake 3.19 or later.
 
 The ``EXACT`` option requests that the version be matched exactly. This option
 is incompatible with the specification of a version range.
@@ -62,36 +144,10 @@ only take the single version at the lower end of the range into account.
 See the :command:`cmake_policy` command documentation for discussion
 of the ``NO_POLICY_SCOPE`` option.
 
-The command has two modes by which it searches for packages: "Module"
-mode and "Config" mode.  The above signature selects Module mode.
-If no module is found the command falls back to Config mode, described
-below. This fall back is disabled if the ``MODULE`` option is given.
-
-In Module mode, CMake searches for a file called ``Find<PackageName>.cmake``.
-The file is first searched in the :variable:`CMAKE_MODULE_PATH`,
-then among the :ref:`Find Modules` provided by the CMake installation.
-If the file is found, it is read and processed by CMake.  It is responsible
-for finding the package, checking the version, and producing any needed
-messages.  Some find-modules provide limited or no support for versioning;
-check the module documentation.
-
-If the ``MODULE`` option is not specified in the above signature,
-CMake first searches for the package using Module mode. Then, if the
-package is not found, it searches again using Config mode. A user
-may set the variable :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` to
-``TRUE`` to direct CMake first search using Config mode before falling
-back to Module mode.
-
-Full Signature and Config Mode
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-User code should generally look for packages using the above `basic
-signature`_.  The remainder of this command documentation specifies the
-full command signature and details of the search process.  Project
-maintainers wishing to provide a package to be found by this command
-are encouraged to read on.
-
-The complete Config mode command signature is
+.. _`full signature`:
+
+Full Signature
+^^^^^^^^^^^^^^
 
 .. code-block:: cmake
 
@@ -129,18 +185,19 @@ hold the directory containing the file.  By default the command
 searches for a package with the name ``<PackageName>``.  If the ``NAMES`` option
 is given the names following it are used instead of ``<PackageName>``.
 The command searches for a file called ``<PackageName>Config.cmake`` or
-``<lower-case-package-name>-config.cmake`` for each name specified.
+``<lowercasePackageName>-config.cmake`` for each name specified.
 A replacement set of possible configuration file names may be given
-using the ``CONFIGS`` option.  The search procedure is specified below.
-Once found, the configuration file is read and processed by CMake.
+using the ``CONFIGS`` option.  The :ref:`search procedure` is specified below.
+Once found, any :ref:`version constraint <version selection>` is checked,
+and if satisfied, the configuration file is read and processed by CMake.
 Since the file is provided by the package it already knows the
 location of package contents.  The full path to the configuration file
 is stored in the cmake variable ``<PackageName>_CONFIG``.
 
 All configuration files which have been considered by CMake while
-searching for an installation of the package with an appropriate
-version are stored in the cmake variable ``<PackageName>_CONSIDERED_CONFIGS``,
-the associated versions in ``<PackageName>_CONSIDERED_VERSIONS``.
+searching for the package with an appropriate version are stored in the
+``<PackageName>_CONSIDERED_CONFIGS`` variable, and the associated versions
+in the ``<PackageName>_CONSIDERED_VERSIONS`` variable.
 
 If the package configuration file cannot be found CMake will generate
 an error describing the problem unless the ``QUIET`` argument is
@@ -150,143 +207,18 @@ fatal error is generated and the configure step stops executing.  If
 configuration file CMake will ignore it and search from scratch.
 
 Package maintainers providing CMake package configuration files are
-encouraged to name and install them such that the `Search Procedure`_
+encouraged to name and install them such that the :ref:`search procedure`
 outlined below will find them without requiring use of additional options.
 
-Version Selection
-^^^^^^^^^^^^^^^^^
+.. _`search procedure`:
 
-When the ``[version]`` argument is given, Config mode will only find a
-version of the package that claims compatibility with the requested
-version (see :ref:`format specification <FIND_PACKAGE_VERSION_FORMAT>`). If the
-``EXACT`` option is given, only a version of the package claiming an exact match
-of the requested version may be found.  CMake does not establish any
-convention for the meaning of version numbers.  Package version
-numbers are checked by "version" files provided by the packages
-themselves.  For a candidate package configuration file
-``<config-file>.cmake`` the corresponding version file is located next
-to it and named either ``<config-file>-version.cmake`` or
-``<config-file>Version.cmake``.  If no such version file is available
-then the configuration file is assumed to not be compatible with any
-requested version.  A basic version file containing generic version
-matching code can be created using the
-:module:`CMakePackageConfigHelpers` module.  When a version file
-is found it is loaded to check the requested version number.  The
-version file is loaded in a nested scope in which the following
-variables have been defined:
+Config Mode Search Procedure
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-``PACKAGE_FIND_NAME``
-  The ``<PackageName>``
-``PACKAGE_FIND_VERSION``
-  Full requested version string
-``PACKAGE_FIND_VERSION_MAJOR``
-  Major version if requested, else 0
-``PACKAGE_FIND_VERSION_MINOR``
-  Minor version if requested, else 0
-``PACKAGE_FIND_VERSION_PATCH``
-  Patch version if requested, else 0
-``PACKAGE_FIND_VERSION_TWEAK``
-  Tweak version if requested, else 0
-``PACKAGE_FIND_VERSION_COUNT``
-  Number of version components, 0 to 4
-
-When a version range is specified, the above version variables will hold
-values based on the lower end of the version range.  This is to preserve
-compatibility with packages that have not been implemented to expect version
-ranges.  In addition, the version range will be described by the following
-variables:
-
-``PACKAGE_FIND_VERSION_RANGE``
-  Full requested version range string
-``PACKAGE_FIND_VERSION_RANGE_MIN``
-  This specifies whether the lower end point of the version range should be
-  included or excluded.  Currently, the only supported value for this variable
-  is ``INCLUDE``.
-``PACKAGE_FIND_VERSION_RANGE_MAX``
-  This specifies whether the upper end point of the version range should be
-  included or excluded.  The supported values for this variable are
-  ``INCLUDE`` and ``EXCLUDE``.
-
-``PACKAGE_FIND_VERSION_MIN``
-  Full requested version string of the lower end point of the range
-``PACKAGE_FIND_VERSION_MIN_MAJOR``
-  Major version of the lower end point if requested, else 0
-``PACKAGE_FIND_VERSION_MIN_MINOR``
-  Minor version of the lower end point if requested, else 0
-``PACKAGE_FIND_VERSION_MIN_PATCH``
-  Patch version of the lower end point if requested, else 0
-``PACKAGE_FIND_VERSION_MIN_TWEAK``
-  Tweak version of the lower end point if requested, else 0
-``PACKAGE_FIND_VERSION_MIN_COUNT``
-  Number of version components of the lower end point, 0 to 4
-
-``PACKAGE_FIND_VERSION_MAX``
-  Full requested version string of the upper end point of the range
-``PACKAGE_FIND_VERSION_MAX_MAJOR``
-  Major version of the upper end point if requested, else 0
-``PACKAGE_FIND_VERSION_MAX_MINOR``
-  Minor version of the upper end point if requested, else 0
-``PACKAGE_FIND_VERSION_MAX_PATCH``
-  Patch version of the upper end point if requested, else 0
-``PACKAGE_FIND_VERSION_MAX_TWEAK``
-  Tweak version of the upper end point if requested, else 0
-``PACKAGE_FIND_VERSION_MAX_COUNT``
-  Number of version components of the upper end point, 0 to 4
-
-Regardless of whether a single version or a version range is specified, the
-variable ``PACKAGE_FIND_VERSION_COMPLETE`` will be defined and will hold
-the full requested version string as specified.
-
-The version file checks whether it satisfies the requested version and
-sets these variables:
-
-``PACKAGE_VERSION``
-  Full provided version string
-``PACKAGE_VERSION_EXACT``
-  True if version is exact match
-``PACKAGE_VERSION_COMPATIBLE``
-  True if version is compatible
-``PACKAGE_VERSION_UNSUITABLE``
-  True if unsuitable as any version
-
-These variables are checked by the ``find_package`` command to determine
-whether the configuration file provides an acceptable version.  They
-are not available after the ``find_package`` call returns.  If the version
-is acceptable the following variables are set:
-
-``<PackageName>_VERSION``
-  Full provided version string
-``<PackageName>_VERSION_MAJOR``
-  Major version if provided, else 0
-``<PackageName>_VERSION_MINOR``
-  Minor version if provided, else 0
-``<PackageName>_VERSION_PATCH``
-  Patch version if provided, else 0
-``<PackageName>_VERSION_TWEAK``
-  Tweak version if provided, else 0
-``<PackageName>_VERSION_COUNT``
-  Number of version components, 0 to 4
-
-and the corresponding package configuration file is loaded.
-When multiple package configuration files are available whose version files
-claim compatibility with the version requested it is unspecified which
-one is chosen: unless the variable :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`
-is set no attempt is made to choose a highest or closest version number.
-
-To control the order in which ``find_package`` checks for compatibility use
-the two variables :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` and
-:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION`.
-For instance in order to select the highest version one can set
-
-.. code-block:: cmake
-
-  SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
-  SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
-
-before calling ``find_package``.
-
-Search Procedure
-^^^^^^^^^^^^^^^^
+.. note::
+  When Config mode is used, this search procedure is applied regardless of
+  whether the :ref:`full <full signature>` or :ref:`basic <basic signature>`
+  signature was given.
 
 CMake constructs a set of possible installation prefixes for the
 package.  Under each prefix several directories are searched for a
@@ -432,7 +364,7 @@ enabled.
    hard-coded guesses.
 
 .. versionadded:: 3.16
-   Added the ``CMAKE_FIND_USE_<CATEGORY>_PATH`` variables to globally disable
+   Added the ``CMAKE_FIND_USE_<CATEGORY>`` variables to globally disable
    various search locations.
 
 .. |FIND_XXX| replace:: find_package
@@ -448,8 +380,154 @@ which the file is found.  The :variable:`CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS`
 variable may be set to ``TRUE`` before calling ``find_package`` in order
 to resolve symbolic links and store the real path to the file.
 
-Every non-REQUIRED ``find_package`` call can be disabled by setting the
-:variable:`CMAKE_DISABLE_FIND_PACKAGE_<PackageName>` variable to ``TRUE``.
+Every non-REQUIRED ``find_package`` call can be disabled or made REQUIRED:
+
+* Setting the :variable:`CMAKE_DISABLE_FIND_PACKAGE_<PackageName>` variable
+  to ``TRUE`` disables the package.
+
+* Setting the :variable:`CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>` variable
+  to ``TRUE`` makes the package REQUIRED.
+
+Setting both variables to ``TRUE`` simultaneously is an error.
+
+.. _`version selection`:
+
+Config Mode Version Selection
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. note::
+  When Config mode is used, this version selection process is applied
+  regardless of whether the :ref:`full <full signature>` or
+  :ref:`basic <basic signature>` signature was given.
+
+When the ``[version]`` argument is given, Config mode will only find a
+version of the package that claims compatibility with the requested
+version (see :ref:`format specification <FIND_PACKAGE_VERSION_FORMAT>`). If the
+``EXACT`` option is given, only a version of the package claiming an exact match
+of the requested version may be found.  CMake does not establish any
+convention for the meaning of version numbers.  Package version
+numbers are checked by "version" files provided by the packages
+themselves.  For a candidate package configuration file
+``<config-file>.cmake`` the corresponding version file is located next
+to it and named either ``<config-file>-version.cmake`` or
+``<config-file>Version.cmake``.  If no such version file is available
+then the configuration file is assumed to not be compatible with any
+requested version.  A basic version file containing generic version
+matching code can be created using the
+:module:`CMakePackageConfigHelpers` module.  When a version file
+is found it is loaded to check the requested version number.  The
+version file is loaded in a nested scope in which the following
+variables have been defined:
+
+``PACKAGE_FIND_NAME``
+  The ``<PackageName>``
+``PACKAGE_FIND_VERSION``
+  Full requested version string
+``PACKAGE_FIND_VERSION_MAJOR``
+  Major version if requested, else 0
+``PACKAGE_FIND_VERSION_MINOR``
+  Minor version if requested, else 0
+``PACKAGE_FIND_VERSION_PATCH``
+  Patch version if requested, else 0
+``PACKAGE_FIND_VERSION_TWEAK``
+  Tweak version if requested, else 0
+``PACKAGE_FIND_VERSION_COUNT``
+  Number of version components, 0 to 4
+
+When a version range is specified, the above version variables will hold
+values based on the lower end of the version range.  This is to preserve
+compatibility with packages that have not been implemented to expect version
+ranges.  In addition, the version range will be described by the following
+variables:
+
+``PACKAGE_FIND_VERSION_RANGE``
+  Full requested version range string
+``PACKAGE_FIND_VERSION_RANGE_MIN``
+  This specifies whether the lower end point of the version range should be
+  included or excluded.  Currently, the only supported value for this variable
+  is ``INCLUDE``.
+``PACKAGE_FIND_VERSION_RANGE_MAX``
+  This specifies whether the upper end point of the version range should be
+  included or excluded.  The supported values for this variable are
+  ``INCLUDE`` and ``EXCLUDE``.
+
+``PACKAGE_FIND_VERSION_MIN``
+  Full requested version string of the lower end point of the range
+``PACKAGE_FIND_VERSION_MIN_MAJOR``
+  Major version of the lower end point if requested, else 0
+``PACKAGE_FIND_VERSION_MIN_MINOR``
+  Minor version of the lower end point if requested, else 0
+``PACKAGE_FIND_VERSION_MIN_PATCH``
+  Patch version of the lower end point if requested, else 0
+``PACKAGE_FIND_VERSION_MIN_TWEAK``
+  Tweak version of the lower end point if requested, else 0
+``PACKAGE_FIND_VERSION_MIN_COUNT``
+  Number of version components of the lower end point, 0 to 4
+
+``PACKAGE_FIND_VERSION_MAX``
+  Full requested version string of the upper end point of the range
+``PACKAGE_FIND_VERSION_MAX_MAJOR``
+  Major version of the upper end point if requested, else 0
+``PACKAGE_FIND_VERSION_MAX_MINOR``
+  Minor version of the upper end point if requested, else 0
+``PACKAGE_FIND_VERSION_MAX_PATCH``
+  Patch version of the upper end point if requested, else 0
+``PACKAGE_FIND_VERSION_MAX_TWEAK``
+  Tweak version of the upper end point if requested, else 0
+``PACKAGE_FIND_VERSION_MAX_COUNT``
+  Number of version components of the upper end point, 0 to 4
+
+Regardless of whether a single version or a version range is specified, the
+variable ``PACKAGE_FIND_VERSION_COMPLETE`` will be defined and will hold
+the full requested version string as specified.
+
+The version file checks whether it satisfies the requested version and
+sets these variables:
+
+``PACKAGE_VERSION``
+  Full provided version string
+``PACKAGE_VERSION_EXACT``
+  True if version is exact match
+``PACKAGE_VERSION_COMPATIBLE``
+  True if version is compatible
+``PACKAGE_VERSION_UNSUITABLE``
+  True if unsuitable as any version
+
+These variables are checked by the ``find_package`` command to determine
+whether the configuration file provides an acceptable version.  They
+are not available after the ``find_package`` call returns.  If the version
+is acceptable the following variables are set:
+
+``<PackageName>_VERSION``
+  Full provided version string
+``<PackageName>_VERSION_MAJOR``
+  Major version if provided, else 0
+``<PackageName>_VERSION_MINOR``
+  Minor version if provided, else 0
+``<PackageName>_VERSION_PATCH``
+  Patch version if provided, else 0
+``<PackageName>_VERSION_TWEAK``
+  Tweak version if provided, else 0
+``<PackageName>_VERSION_COUNT``
+  Number of version components, 0 to 4
+
+and the corresponding package configuration file is loaded.
+When multiple package configuration files are available whose version files
+claim compatibility with the version requested it is unspecified which
+one is chosen: unless the variable :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`
+is set no attempt is made to choose a highest or closest version number.
+
+To control the order in which ``find_package`` checks for compatibility use
+the two variables :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` and
+:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION`.
+For instance in order to select the highest version one can set
+
+.. code-block:: cmake
+
+  SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
+  SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
+
+before calling ``find_package``.
 
 Package File Interface Variables
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -479,7 +557,7 @@ restores their original state before returning):
 ``<PackageName>_FIND_VERSION_EXACT``
   True if ``EXACT`` option was given
 ``<PackageName>_FIND_COMPONENTS``
-  List of requested components
+  List of specified components (required and optional)
 ``<PackageName>_FIND_REQUIRED_<c>``
   True if component ``<c>`` is required,
   false if component ``<c>`` is optional
index f77d8af..46da285 100644 (file)
@@ -9,7 +9,7 @@ Get a property.
                <GLOBAL             |
                 DIRECTORY [<dir>]  |
                 TARGET    <target> |
-                SOURCE    <source> |
+                SOURCE    <source>
                           [DIRECTORY <dir> | TARGET_DIRECTORY <target>] |
                 INSTALL   <file>   |
                 TEST      <test>   |
index fbf3e36..6ff8852 100644 (file)
@@ -171,7 +171,7 @@ Comparisons
 
 ``if(<variable|string> MATCHES regex)``
  True if the given string or variable's value matches the given regular
condition.  See :ref:`Regex Specification` for regex format.
expression.  See :ref:`Regex Specification` for regex format.
 
  .. versionadded:: 3.9
   ``()`` groups are captured in :variable:`CMAKE_MATCH_<n>` variables.
index c6af489..1236f1d 100644 (file)
@@ -30,6 +30,10 @@ are executed in order during installation.
   with those in the parent directory to run in the order declared (see
   policy :policy:`CMP0082`).
 
+.. versionchanged:: 3.22
+  The environment variable :envvar:`CMAKE_INSTALL_MODE` can override the
+  default copying behavior of :command:`install()`.
+
 There are multiple signatures for this command.  Some of them define
 installation options for files and targets.  Options common to
 multiple signatures are covered here but they are valid only for
index f46641f..9b49cb4 100644 (file)
@@ -161,8 +161,9 @@ Inserts elements to the list to the specified location.
 .. versionadded:: 3.15
 
 If no variable name is given, removes exactly one element. Otherwise,
-assign the last element's value to the given variable and removes it,
-up to the last variable name given.
+with `N` variable names provided, assign the last `N` elements' values
+to the given variables and then remove the last `N` values from
+``<list>``.
 
 .. _POP_FRONT:
 
@@ -173,8 +174,9 @@ up to the last variable name given.
 .. versionadded:: 3.15
 
 If no variable name is given, removes exactly one element. Otherwise,
-assign the first element's value to the given variable and removes it,
-up to the last variable name given.
+with `N` variable names provided, assign the first `N` elements' values
+to the given variables and then remove the first `N` values from
+``<list>``.
 
 .. _PREPEND:
 
index bf437b4..555520d 100644 (file)
@@ -9,8 +9,8 @@ Set a named property in a given scope.
                 DIRECTORY [<dir>]           |
                 TARGET    [<target1> ...]   |
                 SOURCE    [<src1> ...]
-                          [DIRECTORY <dirs> ...] |
-                          [TARGET_DIRECTORY <targets> ...]
+                          [DIRECTORY <dirs> ...]
+                          [TARGET_DIRECTORY <targets> ...] |
                 INSTALL   [<file1> ...]     |
                 TEST      [<test1> ...]     |
                 CACHE     [<entry1> ...]    >
index a4b5bf1..83ae286 100644 (file)
@@ -22,7 +22,8 @@ The options are:
  CMake will automatically detect, from ``<src>`` files paths, source groups
  it needs to create, to keep structure of source groups analogically to the
  actual files and directories structure in the project. Paths of ``<src>``
- files will be cut to be relative to ``<root>``.
+ files will be cut to be relative to ``<root>``. The command fails if the
+ paths within ``src`` do not start with ``root``.
 
 ``PREFIX``
  .. versionadded:: 3.8
index 8ad0089..29ad082 100644 (file)
@@ -449,38 +449,73 @@ be in Coordinated Universal Time (UTC) rather than local time.
 The optional ``<format_string>`` may contain the following format
 specifiers:
 
-::
+``%%``
+  .. versionadded:: 3.8
 
-   %%        A literal percent sign (%).
-   %d        The day of the current month (01-31).
-   %H        The hour on a 24-hour clock (00-23).
-   %I        The hour on a 12-hour clock (01-12).
-   %j        The day of the current year (001-366).
-   %m        The month of the current year (01-12).
-   %b        Abbreviated month name (e.g. Oct).
-   %B        Full month name (e.g. October).
-   %M        The minute of the current hour (00-59).
-   %s        Seconds since midnight (UTC) 1-Jan-1970 (UNIX time).
-   %S        The second of the current minute.
-             60 represents a leap second. (00-60)
-   %U        The week number of the current year (00-53).
-   %w        The day of the current week. 0 is Sunday. (0-6)
-   %a        Abbreviated weekday name (e.g. Fri).
-   %A        Full weekday name (e.g. Friday).
-   %y        The last two digits of the current year (00-99)
-   %Y        The current year.
-
-.. versionadded:: 3.6
-  ``%s`` format specifier (UNIX time).
+  A literal percent sign (%).
 
-.. versionadded:: 3.7
-  ``%a`` and ``%b`` format specifiers (abbreviated month and weekday names).
+``%d``
+  The day of the current month (01-31).
 
-.. versionadded:: 3.8
-  ``%%`` specifier (literal ``%``).
+``%H``
+  The hour on a 24-hour clock (00-23).
 
-.. versionadded:: 3.7
-  ``%A`` and ``%B`` format specifiers (full month and weekday names).
+``%I``
+  The hour on a 12-hour clock (01-12).
+
+``%j``
+  The day of the current year (001-366).
+
+``%m``
+  The month of the current year (01-12).
+
+``%b``
+  .. versionadded:: 3.7
+
+  Abbreviated month name (e.g. Oct).
+
+``%B``
+  .. versionadded:: 3.10
+
+  Full month name (e.g. October).
+
+``%M``
+  The minute of the current hour (00-59).
+
+``%s``
+  .. versionadded:: 3.6
+
+  Seconds since midnight (UTC) 1-Jan-1970 (UNIX time).
+
+``%S``
+  The second of the current minute.  60 represents a leap second. (00-60)
+
+``%U``
+  The week number of the current year (00-53).
+
+``%V``
+  .. versionadded:: 3.22
+
+  The ISO 8601 week number of the current year (01-53).
+
+``%w``
+  The day of the current week. 0 is Sunday. (0-6)
+
+``%a``
+  .. versionadded:: 3.7
+
+  Abbreviated weekday name (e.g. Fri).
+
+``%A``
+  .. versionadded:: 3.10
+
+  Full weekday name (e.g. Friday).
+
+``%y``
+  The last two digits of the current year (00-99).
+
+``%Y``
+  The current year.
 
 Unknown format specifiers will be ignored and copied to the output
 as-is.
index 08f8d5b..06da910 100644 (file)
@@ -19,6 +19,10 @@ Try Compiling Whole Projects
 Try building a project.  The success or failure of the ``try_compile``,
 i.e. ``TRUE`` or ``FALSE`` respectively, is returned in ``<resultVar>``.
 
+.. versionadded:: 3.14
+  The name of the ``<resultVar>`` is defined by the user.  Previously, it had
+  a fixed name ``RESULT_VAR``.
+
 In this form, ``<srcdir>`` should contain a complete CMake project with a
 ``CMakeLists.txt`` file and all sources.  The ``<bindir>`` and ``<srcdir>``
 will not be deleted after this command is run.  Specify ``<targetName>`` to
@@ -47,6 +51,10 @@ Try building an executable or static library from one or more source files
 variable).  The success or failure of the ``try_compile``, i.e. ``TRUE`` or
 ``FALSE`` respectively, is returned in ``<resultVar>``.
 
+.. versionadded:: 3.14
+  The name of the ``<resultVar>`` is defined by the user.  Previously, it had
+  a fixed name ``RESULT_VAR``.
+
 In this form, one or more source files must be provided.  If
 :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` is unset or is set to ``EXECUTABLE``,
 the sources must include a definition for ``main`` and CMake will create a
index fc41cdd..404de98 100644 (file)
@@ -30,6 +30,11 @@ executable was built, but failed to run, then ``<runResultVar>`` will be
 set to ``FAILED_TO_RUN``.  See the :command:`try_compile` command for
 information on how the test project is constructed to build the source file.
 
+.. versionadded:: 3.14
+  The names of the result variables ``<runResultVar>`` and
+  ``<compileResultVar>`` are defined by the user.  Previously, they had
+  fixed names ``RUN_RESULT_VAR`` and ``COMPILE_RESULT_VAR``.
+
 The options are:
 
 ``CMAKE_FLAGS <flags>...``
index d8d53ec..f96ca32 100644 (file)
@@ -274,10 +274,23 @@ List of CPack DEB generator specific variables:
 
  Possible values are:
 
- - lzma
- - xz
- - bzip2
- - gzip
+  ``lzma``
+    Lempel–Ziv–Markov chain algorithm
+
+  ``xz``
+    XZ Utils compression
+
+  ``bzip2``
+    bzip2 Burrows–Wheeler algorithm
+
+  ``gzip``
+    GNU Gzip compression
+
+  ``zstd``
+    .. versionadded:: 3.22
+
+    Zstandard compression
+
 
 .. variable:: CPACK_DEBIAN_PACKAGE_PRIORITY
               CPACK_DEBIAN_<COMPONENT>_PACKAGE_PRIORITY
@@ -652,9 +665,18 @@ Dbgsym packaging has its own set of variables:
 
 .. note::
 
+ Setting this also strips the ELF files in the generated non-dbgsym package,
+ which results in debuginfo only being available in the dbgsym package.
+
+.. note::
+
  Binaries must contain debug symbols before packaging so use either ``Debug``
  or ``RelWithDebInfo`` for :variable:`CMAKE_BUILD_TYPE` variable value.
 
+ Additionally, if :variable:`CPACK_STRIP_FILES` is set, the files will be stripped before
+ they get to the DEB generator, so will not contain debug symbols and
+ a dbgsym package will not get built. Do not use with :variable:`CPACK_STRIP_FILES`.
+
 Building Debian packages on Windows
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index 02e33ba..299cfec 100644 (file)
@@ -3,8 +3,8 @@ CPack NSIS Generator
 
 CPack Nullsoft Scriptable Install System (NSIS) generator specific options.
 
-.. versionchanged:: 3.17
- The NSIS generator requires NSIS 3.0 or newer.
+.. versionchanged:: 3.22
+ The NSIS generator requires NSIS 3.03 or newer.
 
 Variables specific to CPack NSIS generator
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -201,3 +201,9 @@ on Windows Nullsoft Scriptable Install System.
  .. versionadded:: 3.21
 
  If set, specify the name of the NSIS executable. Default is ``makensis``.
+
+.. variable:: CPACK_NSIS_IGNORE_LICENSE_PAGE
+
+ .. versionadded:: 3.22
+
+ If set, do not display the page containing the license during installation.
index 322ab68..0d287fc 100644 (file)
@@ -840,6 +840,10 @@ Debuginfo RPM packaging has its own set of variables:
  Binaries must contain debug symbols before packaging so use either ``Debug``
  or ``RelWithDebInfo`` for :variable:`CMAKE_BUILD_TYPE` variable value.
 
+ Additionally, if :variable:`CPACK_STRIP_FILES` is set, the files will be stripped before
+ they get to the RPM generator, so will not contain debug symbols and
+ a debuginfo package will not get built. Do not use with :variable:`CPACK_STRIP_FILES`.
+
 .. note::
 
  Packages generated from packages without binary files, with binary files but
@@ -1023,7 +1027,7 @@ Source RPM packaging has its own set of variables:
  * Mandatory : YES
  * Default   : "/"
 
-.. VARIABLE:: CPACK_RPM_BUILDREQUIRES
+.. variable:: CPACK_RPM_BUILDREQUIRES
 
  List of source rpm build dependencies.
 
@@ -1035,3 +1039,16 @@ Source RPM packaging has its own set of variables:
  example::
 
   set(CPACK_RPM_BUILDREQUIRES "python >= 2.5.0, cmake >= 2.8")
+
+.. variable:: CPACK_RPM_REQUIRES_EXCLUDE_FROM
+
+ .. versionadded:: 3.22
+
+ * Mandatory : NO
+ * Default   : -
+
+ May be used to keep the dependency generator from scanning specific files
+ or directories for dependencies.  Note that you can use a regular
+ expression that matches all of the directories or files, for example::
+
+  set(CPACK_RPM_REQUIRES_EXCLUDE_FROM "bin/libqsqloci.*\\.so.*")
index 29fc880..4a2a5d9 100644 (file)
@@ -92,6 +92,11 @@ literal block after ``::``
  the referenced documents inline as part of the referencing
  document.
 
+``versionadded``, ``versionchanged`` directives
+ Specify that something was added or changed by a named CMake version.
+ The command-line help processor prints the block content as if the lines
+ were normal paragraph text with interpretation.
+
 Inline markup constructs not listed above are printed literally in the
 command-line help output.  We prefer to use inline markup constructs that
 look correct in source form, so avoid use of \\-escapes in favor of inline
diff --git a/Help/envvar/CMAKE_BUILD_TYPE.rst b/Help/envvar/CMAKE_BUILD_TYPE.rst
new file mode 100644 (file)
index 0000000..f798aff
--- /dev/null
@@ -0,0 +1,10 @@
+CMAKE_BUILD_TYPE
+----------------
+
+.. versionadded:: 3.22
+
+.. include:: ENV_VAR.txt
+
+The ``CMAKE_BUILD_TYPE`` environment variable specifies a default value
+for the :variable:`CMAKE_BUILD_TYPE` variable when there is no explicit
+configuration given on the first run while creating a new build tree.
diff --git a/Help/envvar/CMAKE_CONFIGURATION_TYPES.rst b/Help/envvar/CMAKE_CONFIGURATION_TYPES.rst
new file mode 100644 (file)
index 0000000..833aa4a
--- /dev/null
@@ -0,0 +1,11 @@
+CMAKE_CONFIGURATION_TYPES
+-------------------------
+
+.. versionadded:: 3.22
+
+.. include:: ENV_VAR.txt
+
+The ``CMAKE_CONFIGURATION_TYPES`` environment variable specifies a
+default value for the :variable:`CMAKE_CONFIGURATION_TYPES` variable
+when there is no explicit configuration given on the first run while
+creating a new build tree.
diff --git a/Help/envvar/CMAKE_INSTALL_MODE.rst b/Help/envvar/CMAKE_INSTALL_MODE.rst
new file mode 100644 (file)
index 0000000..37db0d7
--- /dev/null
@@ -0,0 +1,37 @@
+CMAKE_INSTALL_MODE
+------------------
+
+.. versionadded:: 3.22
+
+.. include:: ENV_VAR.txt
+
+The ``CMAKE_INSTALL_MODE`` environment variable allows users to operate
+CMake in an alternate mode of :command:`file(INSTALL)` and :command:`install()`.
+
+The default behavior for an installation is to copy a source file from a
+source directory into a destination directory. This environment variable
+however allows the user to override this behavior, causing CMake to create
+symbolic links instead.
+
+.. note::
+  A symbolic link consists of a reference file path rather than contents of its own,
+  hence there are two ways to express the relation, either by a relative or an absolute path.
+
+The following values are allowed for ``CMAKE_INSTALL_MODE``:
+
+* empty, unset or ``COPY``: default behavior, duplicate the file at its destination
+* ``ABS_SYMLINK``: create an *absolute* symbolic link to the source file at the destination *or fail*
+* ``ABS_SYMLINK_OR_COPY``: like ``ABS_SYMLINK`` but silently copy on error
+* ``REL_SYMLINK``: create an *relative* symbolic link to the source file at the destination *or fail*
+* ``REL_SYMLINK_OR_COPY``: like ``REL_SYMLINK`` but silently copy on error
+* ``SYMLINK``: try as if through ``REL_SYMLINK`` and fall back to ``ABS_SYMLINK`` if the referenced
+  file cannot be expressed using a relative path. Fail on error.
+* ``SYMLINK_OR_COPY``: like ``SYMLINK`` but silently copy on error
+
+Installing symbolic links rather than copying files can help conserve storage space because files do
+not have to be duplicated on disk. However, modifications applied to the source immediately affects
+the symbolic link and vice versa. *Use with caution*.
+
+.. note:: ``CMAKE_INSTALL_MODE`` only affects files, *not* directories.
+
+.. note:: Symbolic links are not available on all platforms.
index c065550..9ec33c3 100644 (file)
@@ -1,7 +1,14 @@
 Visual Studio 10 2010
 ---------------------
 
-Generates Visual Studio 10 (VS 2010) project files.
+Deprecated.  Generates Visual Studio 10 (VS 2010) project files.
+
+.. note::
+  This generator is deprecated and will be removed in a future version
+  of CMake.  It will still be possible to build with VS 10 2010 tools
+  using the :generator:`Visual Studio 11 2012` (or above) generator
+  with :variable:`CMAKE_GENERATOR_TOOLSET` set to ``v100``, or by
+  using the :generator:`NMake Makefiles` generator.
 
 For compatibility with CMake versions prior to 3.0, one may specify this
 generator using the name ``Visual Studio 10`` without the year component.
index a4f5f98..b4d6f6d 100644 (file)
@@ -15,20 +15,20 @@ Powershell, Python, etc.) are not supported.
 Instance Selection
 ^^^^^^^^^^^^^^^^^^
 
-.. versionadded:: 3.9
-  VS 2017 supports multiple installations on the same machine.
-  The :variable:`CMAKE_GENERATOR_INSTANCE` variable may be set as a
-  cache entry containing the absolute path to a Visual Studio instance.
-  If the value is not specified explicitly by the user or a toolchain file,
-  CMake queries the Visual Studio Installer to locate VS instances, chooses
-  one, and sets the variable as a cache entry to hold the value persistently.
-
 .. versionadded:: 3.11
-  When CMake first chooses an instance, if the ``VS150COMNTOOLS`` environment
-  variable is set and points to the ``Common7/Tools`` directory within
-  one of the instances, that instance will be used.  Otherwise, if more
-  than one instance is installed we do not define which one is chosen
-  by default.
+
+VS 2017 supports multiple installations on the same machine.
+The :variable:`CMAKE_GENERATOR_INSTANCE` variable may be set as a
+cache entry containing the absolute path to a Visual Studio instance.
+If the value is not specified explicitly by the user or a toolchain file,
+CMake queries the Visual Studio Installer to locate VS instances, chooses
+one, and sets the variable as a cache entry to hold the value persistently.
+
+When CMake first chooses an instance, if the ``VS150COMNTOOLS`` environment
+variable is set and points to the ``Common7/Tools`` directory within
+one of the instances, that instance will be used.  Otherwise, if more
+than one instance is installed we do not define which one is chosen
+by default.
 
 Platform Selection
 ^^^^^^^^^^^^^^^^^^
index 41e8479..cf1ec01 100644 (file)
@@ -24,6 +24,45 @@ Upper, lower, and mixed case commands are supported by CMake. The source
 code for ``tutorial.cxx`` is provided in the ``Step1`` directory and can be
 used to compute the square root of a number.
 
+Build and Run
+-------------
+
+That's all that is needed - we can build and run our project now! First, run
+the :manual:`cmake <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
+with your chosen build tool.
+
+For example, from the command line we could navigate to the
+``Help/guide/tutorial`` directory of the CMake source code tree and create a
+build directory:
+
+.. code-block:: console
+
+  mkdir Step1_build
+
+Next, navigate to the build directory and run CMake to configure the project
+and generate a native build system:
+
+.. code-block:: console
+
+  cd Step1_build
+  cmake ../Step1
+
+Then call that build system to actually compile/link the project:
+
+.. code-block:: console
+
+  cmake --build .
+
+Finally, try to use the newly built ``Tutorial`` with these commands:
+
+.. code-block:: console
+
+  Tutorial 4294967296
+  Tutorial 10
+  Tutorial
+
+
 Adding a Version Number and Configured Header File
 --------------------------------------------------
 
@@ -113,39 +152,24 @@ call to ``add_executable``.
   :language: cmake
   :end-before: # configure a header file to pass some of the CMake settings
 
-Build and Test
---------------
-
-Run the :manual:`cmake <cmake(1)>` executable or the
-:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
-with your chosen build tool.
-
-For example, from the command line we could navigate to the
-``Help/guide/tutorial`` directory of the CMake source code tree and create a
-build directory:
-
-.. code-block:: console
+Rebuild
+-------
 
-  mkdir Step1_build
-
-Next, navigate to the build directory and run CMake to configure the project
-and generate a native build system:
+Let's build our project again. We already created a build directory and ran
+CMake, so we can skip to the build step:
 
 .. code-block:: console
 
   cd Step1_build
-  cmake ../Step1
-
-Then call that build system to actually compile/link the project:
-
-.. code-block:: console
-
   cmake --build .
 
-Finally, try to use the newly built ``Tutorial`` with these commands:
+Now we can try to use the newly built ``Tutorial`` with same commands as before:
 
 .. code-block:: console
 
   Tutorial 4294967296
   Tutorial 10
   Tutorial
+
+Check that the version number is now reported when running the executable without
+any arguments.
index e5ab6a2..3bd6d64 100644 (file)
@@ -12,10 +12,10 @@ packaged.
 
 The first step is to update our :command:`install(TARGETS)` commands to not
 only specify a ``DESTINATION`` but also an ``EXPORT``. The ``EXPORT`` keyword
-generates and installs a CMake file containing code to import all targets
-listed in the install command from the installation tree. So let's go ahead and
-explicitly ``EXPORT`` the ``MathFunctions`` library by updating the ``install``
-command in ``MathFunctions/CMakeLists.txt`` to look like:
+generates a CMake file containing code to import all targets listed in the
+install command from the installation tree. So let's go ahead and explicitly
+``EXPORT`` the ``MathFunctions`` library by updating the ``install`` command
+in ``MathFunctions/CMakeLists.txt`` to look like:
 
 .. literalinclude:: Complete/MathFunctions/CMakeLists.txt
   :caption: MathFunctions/CMakeLists.txt
@@ -82,6 +82,46 @@ bottom of the top-level ``CMakeLists.txt``:
   :name: CMakeLists.txt-install-Config.cmake
   :language: cmake
   :start-after: # install the configuration targets
+  :end-before: # generate the config file
+
+
+Next, we execute the :command:`configure_package_config_file`.  This command
+will configure a provided file but with a few specific differences from the
+standard :command:`configure_file` way.
+To properly utilize this function, the input file should have a single line
+with the text ``@PACKAGE_INIT@`` in addition to the content that is desired.
+That variable will be replaced with a block of code which turns set values into
+relative paths.  These values which are new can be referenced by the same name
+but prepended with a ``PACKAGE_`` prefix.
+
+.. literalinclude:: Step12/CMakeLists.txt
+  :caption: CMakeLists.txt
+  :name: CMakeLists.txt-configure-package-config.cmake
+  :language: cmake
+  :start-after: # install the configuration targets
+  :end-before: # generate the version file
+
+The :command:`write_basic_package_version_file` is next.  This command writes
+a file which is used by the "find_package" document the version and
+compatibility of the desired package.  Here, we use the ``Tutorial_VERSION_*``
+variables and say that it is compatible with ``AnyNewerVersion``, which
+denotes that this version or any higher one are compatible with the requested
+version.
+
+.. literalinclude:: Step12/CMakeLists.txt
+  :caption: CMakeLists.txt
+  :name: CMakeLists.txt-basic-version-file.cmake
+  :language: cmake
+  :start-after: # generate the version file
+  :end-before: # install the generated configuration files
+
+Finally, set both generated files to be installed:
+
+.. literalinclude:: Step12/CMakeLists.txt
+  :caption: CMakeLists.txt
+  :name: CMakeLists.txt-install-configured-files.cmake
+  :language: cmake
+  :start-after: # install the generated configuration files
   :end-before: # generate the export
 
 At this point, we have generated a relocatable CMake Configuration for our
index 55acb34..7fcc97f 100644 (file)
@@ -53,6 +53,16 @@ Would be replaced with:
   :start-after: project(Tutorial VERSION 1.0)
   :end-before: # add compiler warning flags just when building this project via
 
+**Note**:  This upcoming section will require a change to the
+:command:`cmake_minimum_required` usage in the code.  The Generator Expression
+that is about to be used was introduced in `3.15`.  Update the call to require
+that more recent version:
+
+.. code-block:: cmake
+  :caption: CMakeLists.txt
+  :name: CMakeLists.txt-version-update
+
+  cmake_minimum_required(VERSION 3.15)
 
 Next we add the desired compiler warning flags that we want for our project. As
 warning flags vary based on the compiler we use the ``COMPILE_LANG_AND_ID``
index 26aae4f..c6e0fd0 100644 (file)
@@ -28,9 +28,23 @@ With:
 The :module:`CTest` module will automatically call ``enable_testing()``, so we
 can remove it from our CMake files.
 
-We will also need to create a ``CTestConfig.cmake`` file in the top-level
-directory where we can specify the name of the project and where to submit the
-dashboard.
+We will also need to acquire a ``CTestConfig.cmake`` file to be placed in the
+top-level directory where we can specify information to CTest about the
+project. It contains:
+
+* The project name
+
+* The project "Nightly" start time
+
+  *  The time when a 24 hour "day" starts for this project.
+
+* The URL of the CDash instance where the submission's generated documents
+  will be sent
+
+One has been provided for you in this directory.  It would normally be
+downloaded from the ``Settings`` page of the project on the CDash
+instance that will host and display the test results.  Once downloaded from
+CDash, the file should not be modified locally.
 
 .. literalinclude:: Step9/CTestConfig.cmake
   :caption: CTestConfig.cmake
index 7210a8d..e149110 100644 (file)
@@ -14,11 +14,14 @@ these functions using the :module:`CheckSymbolExists` module in
 the ``m`` library. If ``log`` and ``exp`` are not initially found, require the
 ``m`` library and try again.
 
+Add the checks for ``log`` and ``exp`` to ``MathFunctions/CMakeLists.txt``,
+after the call to :command:`target_include_directories`:
+
 .. literalinclude:: Step6/MathFunctions/CMakeLists.txt
   :caption: MathFunctions/CMakeLists.txt
   :name: MathFunctions/CMakeLists.txt-check_symbol_exists
   :language: cmake
-  :start-after: # does this system provide the log and exp functions?
+  :start-after: # to find MathFunctions.h, while we don't.
   :end-before: # add compile definitions
 
 If available, use :command:`target_compile_definitions` to specify
index 1806361..ed03448 100644 (file)
@@ -64,8 +64,13 @@ will be stored in the cache so that the user does not need to set the value
 each time they run CMake on a build directory.
 
 The next change is to make building and linking the ``MathFunctions`` library
-conditional. To do this we change the end of the top-level ``CMakeLists.txt``
-file to look like the following:
+conditional. To do this,  we will create an ``if`` statement which checks the
+value of the option.  Inside the ``if`` block, put the
+:command:`add_subdirectory` command from above with some additional list
+commands to store information needed to link to the library and add the
+subdirectory as an include directory in the ``Tutorial`` target.
+The end of the top-level ``CMakeLists.txt`` file will now look like the
+following:
 
 .. literalinclude:: Step3/CMakeLists.txt
   :caption: CMakeLists.txt
index 4d8a3ad..ac1d083 100644 (file)
@@ -73,7 +73,7 @@ function(do_test target arg result)
   set_tests_properties(Comp${arg}
     PROPERTIES PASS_REGULAR_EXPRESSION ${result}
     )
-endfunction(do_test)
+endfunction()
 
 # do a bunch of result based tests
 do_test(Tutorial 4 "4 is 2")
@@ -81,7 +81,7 @@ do_test(Tutorial 9 "9 is 3")
 do_test(Tutorial 5 "5 is 2.236")
 do_test(Tutorial 7 "7 is 2.645")
 do_test(Tutorial 25 "25 is 5")
-do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial -25 "-25 is (-nan|nan|0)")
 do_test(Tutorial 0.0001 "0.0001 is 0.01")
 
 include(InstallRequiredSystemLibraries)
index 2fc3202..394c986 100644 (file)
@@ -88,6 +88,8 @@ input, and expected results based on the passed arguments.
 Rebuild the application and then cd to the binary directory and run the
 :manual:`ctest <ctest(1)>` executable: ``ctest -N`` and ``ctest -VV``. For
 multi-config generators (e.g. Visual Studio), the configuration type must be
-specified. To run tests in Debug mode, for example, use ``ctest -C Debug -VV``
-from the build directory (not the Debug subdirectory!). Alternatively, build
-the ``RUN_TESTS`` target from the IDE.
+specified with the ``-C <mode>`` flag.  For example, to run tests in Debug
+mode use ``ctest -C Debug -VV`` from the binary directory
+(not the Debug subdirectory!). Release mode would be executed from the same
+location but with a ``-C Release``.  Alternatively, build the ``RUN_TESTS``
+target from the IDE.
index 34ae70c..dc9a0e8 100644 (file)
@@ -55,7 +55,7 @@ function(do_test target arg result)
   set_tests_properties(Comp${arg}
     PROPERTIES PASS_REGULAR_EXPRESSION ${result}
     )
-endfunction(do_test)
+endfunction()
 
 # do a bunch of result based tests
 do_test(Tutorial 4 "4 is 2")
@@ -63,7 +63,7 @@ do_test(Tutorial 9 "9 is 3")
 do_test(Tutorial 5 "5 is 2.236")
 do_test(Tutorial 7 "7 is 2.645")
 do_test(Tutorial 25 "25 is 5")
-do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial -25 "-25 is (-nan|nan|0)")
 do_test(Tutorial 0.0001 "0.0001 is 0.01")
 
 include(InstallRequiredSystemLibraries)
index 4763951..10f35ce 100644 (file)
@@ -63,7 +63,7 @@ function(do_test target arg result)
   set_tests_properties(Comp${arg}
     PROPERTIES PASS_REGULAR_EXPRESSION ${result}
     )
-endfunction(do_test)
+endfunction()
 
 # do a bunch of result based tests
 do_test(Tutorial 4 "4 is 2")
@@ -71,7 +71,7 @@ do_test(Tutorial 9 "9 is 3")
 do_test(Tutorial 5 "5 is 2.236")
 do_test(Tutorial 7 "7 is 2.645")
 do_test(Tutorial 25 "25 is 5")
-do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial -25 "-25 is (-nan|nan|0)")
 do_test(Tutorial 0.0001 "0.0001 is 0.01")
 
 include(InstallRequiredSystemLibraries)
index 1b0c826..634b84c 100644 (file)
@@ -69,7 +69,7 @@ function(do_test target arg result)
   set_tests_properties(Comp${arg}
     PROPERTIES PASS_REGULAR_EXPRESSION ${result}
     )
-endfunction(do_test)
+endfunction()
 
 # do a bunch of result based tests
 do_test(Tutorial 4 "4 is 2")
@@ -77,7 +77,7 @@ do_test(Tutorial 9 "9 is 3")
 do_test(Tutorial 5 "5 is 2.236")
 do_test(Tutorial 7 "7 is 2.645")
 do_test(Tutorial 25 "25 is 5")
-do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial -25 "-25 is (-nan|nan|0)")
 do_test(Tutorial 0.0001 "0.0001 is 0.01")
 
 include(InstallRequiredSystemLibraries)
@@ -107,7 +107,7 @@ write_basic_package_version_file(
   COMPATIBILITY AnyNewerVersion
 )
 
-# install the configuration file
+# install the generated configuration files
 install(FILES
   ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
   ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake
index c3b375a..82d00c8 100644 (file)
@@ -54,7 +54,7 @@ function(do_test target arg result)
   set_tests_properties(Comp${arg}
     PROPERTIES PASS_REGULAR_EXPRESSION ${result}
     )
-endfunction(do_test)
+endfunction()
 
 # do a bunch of result based tests
 do_test(Tutorial 4 "4 is 2")
@@ -62,5 +62,5 @@ do_test(Tutorial 9 "9 is 3")
 do_test(Tutorial 5 "5 is 2.236")
 do_test(Tutorial 7 "7 is 2.645")
 do_test(Tutorial 25 "25 is 5")
-do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial -25 "-25 is (-nan|nan|0)")
 do_test(Tutorial 0.0001 "0.0001 is 0.01")
index c3b375a..82d00c8 100644 (file)
@@ -54,7 +54,7 @@ function(do_test target arg result)
   set_tests_properties(Comp${arg}
     PROPERTIES PASS_REGULAR_EXPRESSION ${result}
     )
-endfunction(do_test)
+endfunction()
 
 # do a bunch of result based tests
 do_test(Tutorial 4 "4 is 2")
@@ -62,5 +62,5 @@ do_test(Tutorial 9 "9 is 3")
 do_test(Tutorial 5 "5 is 2.236")
 do_test(Tutorial 7 "7 is 2.645")
 do_test(Tutorial 25 "25 is 5")
-do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial -25 "-25 is (-nan|nan|0)")
 do_test(Tutorial 0.0001 "0.0001 is 0.01")
index c3b375a..82d00c8 100644 (file)
@@ -54,7 +54,7 @@ function(do_test target arg result)
   set_tests_properties(Comp${arg}
     PROPERTIES PASS_REGULAR_EXPRESSION ${result}
     )
-endfunction(do_test)
+endfunction()
 
 # do a bunch of result based tests
 do_test(Tutorial 4 "4 is 2")
@@ -62,5 +62,5 @@ do_test(Tutorial 9 "9 is 3")
 do_test(Tutorial 5 "5 is 2.236")
 do_test(Tutorial 7 "7 is 2.645")
 do_test(Tutorial 25 "25 is 5")
-do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial -25 "-25 is (-nan|nan|0)")
 do_test(Tutorial 0.0001 "0.0001 is 0.01")
index 19b9913..4ae898f 100644 (file)
@@ -54,7 +54,7 @@ function(do_test target arg result)
   set_tests_properties(Comp${arg}
     PROPERTIES PASS_REGULAR_EXPRESSION ${result}
     )
-endfunction(do_test)
+endfunction()
 
 # do a bunch of result based tests
 do_test(Tutorial 4 "4 is 2")
@@ -62,7 +62,7 @@ do_test(Tutorial 9 "9 is 3")
 do_test(Tutorial 5 "5 is 2.236")
 do_test(Tutorial 7 "7 is 2.645")
 do_test(Tutorial 25 "25 is 5")
-do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial -25 "-25 is (-nan|nan|0)")
 do_test(Tutorial 0.0001 "0.0001 is 0.01")
 
 # setup installer
diff --git a/Help/guide/tutorial/Step8/CTestConfig.cmake b/Help/guide/tutorial/Step8/CTestConfig.cmake
new file mode 100644 (file)
index 0000000..73efdb1
--- /dev/null
@@ -0,0 +1,7 @@
+set(CTEST_PROJECT_NAME "CMakeTutorial")
+set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
+
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "my.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
+set(CTEST_DROP_SITE_CDASH TRUE)
index d5f1cc8..130bc9a 100644 (file)
@@ -54,7 +54,7 @@ function(do_test target arg result)
   set_tests_properties(Comp${arg}
     PROPERTIES PASS_REGULAR_EXPRESSION ${result}
     )
-endfunction(do_test)
+endfunction()
 
 # do a bunch of result based tests
 do_test(Tutorial 4 "4 is 2")
@@ -62,7 +62,7 @@ do_test(Tutorial 9 "9 is 3")
 do_test(Tutorial 5 "5 is 2.236")
 do_test(Tutorial 7 "7 is 2.645")
 do_test(Tutorial 25 "25 is 5")
-do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial -25 "-25 is (-nan|nan|0)")
 do_test(Tutorial 0.0001 "0.0001 is 0.01")
 
 include(InstallRequiredSystemLibraries)
index 7008383..2f43070 100644 (file)
@@ -21,9 +21,9 @@ Binary Targets
 
 Executables and libraries are defined using the :command:`add_executable`
 and :command:`add_library` commands.  The resulting binary files have
-appropriate :prop_tgt:`PREFIX`, :prop_tgt:`SUFFIX` and extensions for the platform targeted.
-Dependencies between binary targets are expressed using the
-:command:`target_link_libraries` command:
+appropriate :prop_tgt:`PREFIX`, :prop_tgt:`SUFFIX` and extensions for the
+platform targeted. Dependencies between binary targets are expressed using
+the :command:`target_link_libraries` command:
 
 .. code-block:: cmake
 
@@ -530,38 +530,6 @@ the calculated "compatible" value of a property may be read with the
 In this case, the ``exe1`` source files will be compiled with
 ``-DCONTAINER_SIZE=200``.
 
-Configuration determined build specifications may be conveniently set using
-the ``CONFIG`` generator expression.
-
-.. code-block:: cmake
-
-  target_compile_definitions(exe1 PRIVATE
-      $<$<CONFIG:Debug>:DEBUG_BUILD>
-  )
-
-The ``CONFIG`` parameter is compared case-insensitively with the configuration
-being built.  In the presence of :prop_tgt:`IMPORTED` targets, the content of
-:prop_tgt:`MAP_IMPORTED_CONFIG_DEBUG <MAP_IMPORTED_CONFIG_<CONFIG>>` is also
-accounted for by this expression.
-
-Some buildsystems generated by :manual:`cmake(1)` have a predetermined
-build-configuration set in the :variable:`CMAKE_BUILD_TYPE` variable.  The
-buildsystem for the IDEs such as Visual Studio and Xcode are generated
-independent of the build-configuration, and the actual build configuration
-is not known until build-time.  Therefore, code such as
-
-.. code-block:: cmake
-
-  string(TOLOWER ${CMAKE_BUILD_TYPE} _type)
-  if (_type STREQUAL debug)
-    target_compile_definitions(exe1 PRIVATE DEBUG_BUILD)
-  endif()
-
-may appear to work for :ref:`Makefile Generators` and :generator:`Ninja`
-generators, but is not portable to IDE generators.  Additionally,
-the :prop_tgt:`IMPORTED` configuration-mappings are not accounted for
-with code like this, so it should be avoided.
-
 The unary ``TARGET_PROPERTY`` generator expression and the ``TARGET_POLICY``
 generator expression are evaluated with the consuming target context.  This
 means that a usage requirement specification may be evaluated differently based
@@ -840,6 +808,121 @@ target at a time.  The commands :command:`add_compile_definitions`,
 a similar function, but operate at directory scope instead of target
 scope for convenience.
 
+.. _`Build Configurations`:
+
+Build Configurations
+====================
+
+Configurations determine specifications for a certain type of build, such
+as ``Release`` or ``Debug``.  The way this is specified depends on the type
+of :manual:`generator <cmake-generators(7)>` being used.  For single
+configuration generators like  :ref:`Makefile Generators` and
+:generator:`Ninja`, the configuration is specified at configure time by the
+:variable:`CMAKE_BUILD_TYPE` variable. For multi-configuration generators
+like :ref:`Visual Studio <Visual Studio Generators>`, :generator:`Xcode`, and
+:generator:`Ninja Multi-Config`, the configuration is chosen by the user at
+build time and :variable:`CMAKE_BUILD_TYPE` is ignored.  In the
+multi-configuration case, the set of *available* configurations is specified
+at configure time by the :variable:`CMAKE_CONFIGURATION_TYPES` variable,
+but the actual configuration used cannot be known until the build stage.
+This difference is often misunderstood, leading to problematic code like the
+following:
+
+.. code-block:: cmake
+
+  # WARNING: This is wrong for multi-config generators because they don't use
+  #          and typically don't even set CMAKE_BUILD_TYPE
+  string(TOLOWER ${CMAKE_BUILD_TYPE} build_type)
+  if (build_type STREQUAL debug)
+    target_compile_definitions(exe1 PRIVATE DEBUG_BUILD)
+  endif()
+
+:manual:`Generator expressions <cmake-generator-expressions(7)>` should be
+used instead to handle configuration-specific logic correctly, regardless of
+the generator used.  For example:
+
+.. code-block:: cmake
+
+  # Works correctly for both single and multi-config generators
+  target_compile_definitions(exe1 PRIVATE
+    $<$<CONFIG:Debug>:DEBUG_BUILD>
+  )
+
+In the presence of :prop_tgt:`IMPORTED` targets, the content of
+:prop_tgt:`MAP_IMPORTED_CONFIG_DEBUG <MAP_IMPORTED_CONFIG_<CONFIG>>` is also
+accounted for by the above ``$<CONFIG:Debug>`` expression.
+
+
+Case Sensitivity
+----------------
+
+:variable:`CMAKE_BUILD_TYPE` and :variable:`CMAKE_CONFIGURATION_TYPES` are
+just like other variables in that any string comparisons made with their
+values will be case-sensitive.  The ``$<CONFIG>`` generator expression also
+preserves the casing of the configuration as set by the user or CMake defaults.
+For example:
+
+.. code-block:: cmake
+
+  # NOTE: Don't use these patterns, they are for illustration purposes only.
+
+  set(CMAKE_BUILD_TYPE Debug)
+  if(CMAKE_BUILD_TYPE STREQUAL DEBUG)
+    # ... will never get here, "Debug" != "DEBUG"
+  endif()
+  add_custom_target(print_config ALL
+    # Prints "Config is Debug" in this single-config case
+    COMMAND ${CMAKE_COMMAND} -E echo "Config is $<CONFIG>"
+    VERBATIM
+  )
+
+  set(CMAKE_CONFIGURATION_TYPES Debug Release)
+  if(DEBUG IN_LIST CMAKE_CONFIGURATION_TYPES)
+    # ... will never get here, "Debug" != "DEBUG"
+  endif()
+
+In contrast, CMake treats the configuration type case-insensitively when
+using it internally in places that modify behavior based on the configuration.
+For example, the ``$<CONFIG:Debug>`` generator expression will evaluate to 1
+for a configuration of not only ``Debug``, but also ``DEBUG``, ``debug`` or
+even ``DeBuG``.  Therefore, you can specify configuration types in
+:variable:`CMAKE_BUILD_TYPE` and :variable:`CMAKE_CONFIGURATION_TYPES` with
+any mixture of upper and lowercase, although there are strong conventions
+(see the next section).  If you must test the value in string comparisons,
+always convert the value to upper or lowercase first and adjust the test
+accordingly.
+
+Default And Custom Configurations
+---------------------------------
+
+By default, CMake defines a number of standard configurations:
+
+* ``Debug``
+* ``Release``
+* ``RelWithDebInfo``
+* ``MinSizeRel``
+
+In multi-config generators, the :variable:`CMAKE_CONFIGURATION_TYPES` variable
+will be populated with (potentially a subset of) the above list by default,
+unless overridden by the project or user.  The actual configuration used is
+selected by the user at build time.
+
+For single-config generators, the configuration is specified with the
+:variable:`CMAKE_BUILD_TYPE` variable at configure time and cannot be changed
+at build time.  The default value will often be none of the above standard
+configurations and will instead be an empty string.  A common misunderstanding
+is that this is the same as ``Debug``, but that is not the case.  Users should
+always explicitly specify the build type instead to avoid this common problem.
+
+The above standard configuration types provide reasonable behavior on most
+platforms, but they can be extended to provide other types.  Each configuration
+defines a set of compiler and linker flag variables for the language in use.
+These variables follow the convention :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>`,
+where ``<CONFIG>`` is always the uppercase configuration name.  When defining
+a custom configuration type, make sure these variables are set appropriately,
+typically as cache variables.
+
+
 Pseudo Targets
 ==============
 
index 2b0de11..67b0f6e 100644 (file)
@@ -118,13 +118,12 @@ as well as any dependents (that may include headers from ``mylib``).
 Availability of Compiler Extensions
 -----------------------------------
 
-Because the :prop_tgt:`CXX_EXTENSIONS` target property is ``ON`` by default,
-CMake uses extended variants of language dialects by default, such as
-``-std=gnu++11`` instead of ``-std=c++11``.  That target property may be
-set to ``OFF`` to use the non-extended variant of the dialect flag.  Note
-that because most compilers enable extensions by default, this could
-expose cross-platform bugs in user code or in the headers of third-party
-dependencies.
+The :prop_tgt:`<LANG>_EXTENSIONS` target property defaults to the compiler's
+default (see :variable:`CMAKE_<LANG>_EXTENSIONS_DEFAULT`). Note that because
+most compilers enable extensions by default, this may expose portability bugs
+in user code or in the headers of third-party dependencies.
+
+:prop_tgt:`<LANG>_EXTENSIONS` used to default to ``ON``. See :policy:`CMP0128`.
 
 Optional Compile Features
 =========================
index fa38588..0799fdd 100644 (file)
@@ -30,12 +30,15 @@ Environment Variables that Control the Build
 
    /envvar/CMAKE_APPLE_SILICON_PROCESSOR
    /envvar/CMAKE_BUILD_PARALLEL_LEVEL
+   /envvar/CMAKE_BUILD_TYPE
+   /envvar/CMAKE_CONFIGURATION_TYPES
    /envvar/CMAKE_CONFIG_TYPE
    /envvar/CMAKE_EXPORT_COMPILE_COMMANDS
    /envvar/CMAKE_GENERATOR
    /envvar/CMAKE_GENERATOR_INSTANCE
    /envvar/CMAKE_GENERATOR_PLATFORM
    /envvar/CMAKE_GENERATOR_TOOLSET
+   /envvar/CMAKE_INSTALL_MODE
    /envvar/CMAKE_LANG_COMPILER_LAUNCHER
    /envvar/CMAKE_LANG_LINKER_LAUNCHER
    /envvar/CMAKE_MSVCIDE_RUN_PATH
index d3cbd49..df13dd0 100644 (file)
@@ -134,8 +134,8 @@ Variable Queries
 
 .. genex:: $<CONFIG:cfgs>
 
-  ``1`` if config is any one of the entries in ``cfgs``, else ``0``. This is a
-  case-insensitive comparison. The mapping in
+  ``1`` if config is any one of the entries in comma-separated list
+  ``cfgs``, else ``0``. This is a case-insensitive comparison. The mapping in
   :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` is also considered by this
   expression when it is evaluated on a property on an :prop_tgt:`IMPORTED`
   target.
index 4b2934a..5c109ff 100644 (file)
@@ -74,7 +74,9 @@ package.
 
 By setting the :variable:`CMAKE_DISABLE_FIND_PACKAGE_<PackageName>` variable to
 ``TRUE``, the ``<PackageName>`` package will not be searched, and will always
-be ``NOTFOUND``.
+be ``NOTFOUND``. Likewise, setting the
+:variable:`CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>` to ``TRUE`` will make the
+package REQUIRED.
 
 .. _`Config File Packages`:
 
@@ -447,7 +449,7 @@ be true. This can be tested with logic in the package configuration file:
   set(_supported_components Plot Table)
 
   foreach(_comp ${ClimbingStats_FIND_COMPONENTS})
-    if (NOT ";${_supported_components};" MATCHES _comp)
+    if (NOT ";${_supported_components};" MATCHES ";${_comp};")
       set(ClimbingStats_FOUND False)
       set(ClimbingStats_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}")
     endif()
index b9e3d45..3df4f9f 100644 (file)
@@ -51,6 +51,15 @@ The :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` variable may also be used
 to determine whether to report an error on use of deprecated macros or
 functions.
 
+Policies Introduced by CMake 3.22
+=================================
+
+.. toctree::
+   :maxdepth: 1
+
+   CMP0128: Selection of language standard and extension flags improved. </policy/CMP0128>
+   CMP0127: cmake_dependent_option() supports full Condition Syntax. </policy/CMP0127>
+
 Policies Introduced by CMake 3.21
 =================================
 
index 5f18a82..bb5dba3 100644 (file)
@@ -202,6 +202,7 @@ Properties on Targets
    /prop_tgt/EXPORT_NAME
    /prop_tgt/EXPORT_PROPERTIES
    /prop_tgt/FOLDER
+   /prop_tgt/Fortran_BUILDING_INSTRINSIC_MODULES
    /prop_tgt/Fortran_FORMAT
    /prop_tgt/Fortran_MODULE_DIRECTORY
    /prop_tgt/Fortran_PREPROCESS
@@ -214,6 +215,9 @@ Properties on Targets
    /prop_tgt/GNUtoMS
    /prop_tgt/HAS_CXX
    /prop_tgt/HIP_ARCHITECTURES
+   /prop_tgt/HIP_EXTENSIONS
+   /prop_tgt/HIP_STANDARD
+   /prop_tgt/HIP_STANDARD_REQUIRED
    /prop_tgt/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
    /prop_tgt/IMPORTED
    /prop_tgt/IMPORTED_COMMON_LANGUAGE_RUNTIME
@@ -273,8 +277,11 @@ Properties on Targets
    /prop_tgt/LANG_COMPILER_LAUNCHER
    /prop_tgt/LANG_CPPCHECK
    /prop_tgt/LANG_CPPLINT
+   /prop_tgt/LANG_EXTENSIONS
    /prop_tgt/LANG_INCLUDE_WHAT_YOU_USE
    /prop_tgt/LANG_LINKER_LAUNCHER
+   /prop_tgt/LANG_STANDARD
+   /prop_tgt/LANG_STANDARD_REQUIRED
    /prop_tgt/LANG_VISIBILITY_PRESET
    /prop_tgt/LIBRARY_OUTPUT_DIRECTORY
    /prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG
@@ -450,6 +457,7 @@ Properties on Tests
    /prop_test/DEPENDS
    /prop_test/DISABLED
    /prop_test/ENVIRONMENT
+   /prop_test/ENVIRONMENT_MODIFICATION
    /prop_test/FAIL_REGULAR_EXPRESSION
    /prop_test/FIXTURES_CLEANUP
    /prop_test/FIXTURES_REQUIRED
index 9cea0fb..4ed0b2e 100644 (file)
@@ -71,6 +71,7 @@ Variables that Provide Information
    /variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER
    /variable/CMAKE_JOB_POOLS
    /variable/CMAKE_LANG_COMPILER_AR
+   /variable/CMAKE_LANG_COMPILER_FRONTEND_VARIANT
    /variable/CMAKE_LANG_COMPILER_RANLIB
    /variable/CMAKE_LANG_LINK_LIBRARY_SUFFIX
    /variable/CMAKE_LINK_LIBRARY_SUFFIX
@@ -124,6 +125,9 @@ Variables that Provide Information
    /variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR
    /variable/CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE
    /variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION
+   /variable/CMAKE_VS_TARGET_FRAMEWORK_VERSION
+   /variable/CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER
+   /variable/CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION
    /variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
    /variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM
    /variable/CMAKE_XCODE_BUILD_SYSTEM
@@ -231,6 +235,7 @@ Variables that Change Behavior
    /variable/CMAKE_PROJECT_INCLUDE_BEFORE
    /variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE
    /variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE
+   /variable/CMAKE_REQUIRE_FIND_PACKAGE_PackageName
    /variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
    /variable/CMAKE_STAGING_PREFIX
    /variable/CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS
@@ -246,6 +251,7 @@ Variables that Change Behavior
    /variable/CMAKE_SYSTEM_LIBRARY_PATH
    /variable/CMAKE_SYSTEM_PREFIX_PATH
    /variable/CMAKE_SYSTEM_PROGRAM_PATH
+   /variable/CMAKE_TLS_CAINFO
    /variable/CMAKE_TLS_VERIFY
    /variable/CMAKE_USER_MAKE_RULES_OVERRIDE
    /variable/CMAKE_WARN_DEPRECATED
@@ -428,6 +434,7 @@ Variables that Control the Build
    /variable/CMAKE_LANG_LINKER_LAUNCHER
    /variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG
    /variable/CMAKE_LANG_LINK_LIBRARY_FLAG
+   /variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG
    /variable/CMAKE_LANG_VISIBILITY_PRESET
    /variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY
    /variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY_CONFIG
@@ -438,6 +445,7 @@ Variables that Control the Build
    /variable/CMAKE_LINK_LIBRARY_FILE_FLAG
    /variable/CMAKE_LINK_LIBRARY_FLAG
    /variable/CMAKE_LINK_WHAT_YOU_USE
+   /variable/CMAKE_LINK_WHAT_YOU_USE_CHECK
    /variable/CMAKE_MACOSX_BUNDLE
    /variable/CMAKE_MACOSX_RPATH
    /variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG
@@ -525,6 +533,9 @@ Variables for Languages
    /variable/CMAKE_Fortran_MODDIR_FLAG
    /variable/CMAKE_Fortran_MODOUT_FLAG
    /variable/CMAKE_HIP_ARCHITECTURES
+   /variable/CMAKE_HIP_EXTENSIONS
+   /variable/CMAKE_HIP_STANDARD
+   /variable/CMAKE_HIP_STANDARD_REQUIRED
    /variable/CMAKE_ISPC_HEADER_DIRECTORY
    /variable/CMAKE_ISPC_HEADER_SUFFIX
    /variable/CMAKE_ISPC_INSTRUCTION_SETS
@@ -546,6 +557,8 @@ Variables for Languages
    /variable/CMAKE_LANG_CREATE_SHARED_LIBRARY
    /variable/CMAKE_LANG_CREATE_SHARED_MODULE
    /variable/CMAKE_LANG_CREATE_STATIC_LIBRARY
+   /variable/CMAKE_LANG_EXTENSIONS
+   /variable/CMAKE_LANG_EXTENSIONS_DEFAULT
    /variable/CMAKE_LANG_FLAGS
    /variable/CMAKE_LANG_FLAGS_CONFIG
    /variable/CMAKE_LANG_FLAGS_CONFIG_INIT
@@ -574,8 +587,11 @@ Variables for Languages
    /variable/CMAKE_LANG_SIMULATE_VERSION
    /variable/CMAKE_LANG_SIZEOF_DATA_PTR
    /variable/CMAKE_LANG_SOURCE_FILE_EXTENSIONS
+   /variable/CMAKE_LANG_STANDARD
+   /variable/CMAKE_LANG_STANDARD_DEFAULT
    /variable/CMAKE_LANG_STANDARD_INCLUDE_DIRECTORIES
    /variable/CMAKE_LANG_STANDARD_LIBRARIES
+   /variable/CMAKE_LANG_STANDARD_REQUIRED
    /variable/CMAKE_OBJC_EXTENSIONS
    /variable/CMAKE_OBJC_STANDARD
    /variable/CMAKE_OBJC_STANDARD_REQUIRED
index 03d8bf6..d66c5a9 100644 (file)
@@ -464,6 +464,10 @@ CTest prints timing summary information for each ``LABEL`` and subproject
 associated with the tests run. The label time summary will not include labels
 that are mapped to subprojects.
 
+.. versionadded:: 3.22
+  Labels added dynamically during test execution are also reported in the
+  timing summary.  See :ref:`Additional Labels`.
+
 When the :prop_test:`PROCESSORS` test property is set, CTest will display a
 weighted test timing result in label and subproject summaries. The time is
 reported with `sec*proc` instead of just `sec`.
index 767e80b..7852550 100644 (file)
               },
               {
                 "type": "array",
-                "description": "An optional array of strings representing the names of presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json may not inherit from presets in CMakeUserPresets.json.",
+                "description": "An optional array of strings representing the names of presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json must not inherit from presets in CMakeUserPresets.json.",
                 "items": {
                   "type": "string",
                   "description": "An optional string representing the name of the preset to inherit from.",
               },
               {
                 "type": "array",
-                "description": "An optional array of strings representing the names of build presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json may not inherit from presets in CMakeUserPresets.json.",
+                "description": "An optional array of strings representing the names of build presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json must not inherit from presets in CMakeUserPresets.json.",
                 "items": {
                   "type": "string",
                   "description": "An optional string representing the name of the preset to inherit from.",
               },
               {
                 "type": "array",
-                "description": "An optional array of strings representing the names of test presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json may not inherit from presets in CMakeUserPresets.json.",
+                "description": "An optional array of strings representing the names of test presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json must not inherit from presets in CMakeUserPresets.json.",
                 "items": {
                   "type": "string",
                   "description": "An optional string representing the name of the preset to inherit from.",
diff --git a/Help/policy/CMP0127.rst b/Help/policy/CMP0127.rst
new file mode 100644 (file)
index 0000000..2106110
--- /dev/null
@@ -0,0 +1,34 @@
+CMP0127
+-------
+
+.. versionadded:: 3.22
+
+:command:`cmake_dependent_option` supports full :ref:`Condition Syntax`.
+
+The ``<depends>`` parameter accepts a :ref:`semicolon-separated list <CMake
+Language Lists>` of conditions.  CMake 3.21 and lower evaluates each
+``condition`` as ``if(${condition})``, which does not properly handle
+conditions with nested paren groups.  CMake 3.22 and above instead prefer
+to evaluate each ``condition`` as ``if(<condition>)``, where ``<condition>``
+is re-parsed as if literally written in a call to :command:`if`.  This
+allows expressions like::
+
+  "A AND (B OR C)"
+
+but requires expressions like::
+
+  "FOO MATCHES (UPPER|lower)"
+
+to be re-written as::
+
+  "FOO MATCHES \"(UPPER|lower)\""
+
+Policy ``CMP0127`` provides compatibility for projects that have not
+been updated to expect the new behavior.
+
+This policy was introduced in CMake version 3.22.  CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0128.rst b/Help/policy/CMP0128.rst
new file mode 100644 (file)
index 0000000..604a146
--- /dev/null
@@ -0,0 +1,71 @@
+CMP0128
+-------
+
+.. versionadded:: 3.22
+
+When this policy is set to ``NEW``:
+
+* :prop_tgt:`<LANG>_EXTENSIONS` is initialized to
+  :variable:`CMAKE_<LANG>_EXTENSIONS` if set, otherwise falling back to
+  :variable:`CMAKE_<LANG>_EXTENSIONS_DEFAULT`.
+
+* Extensions are correctly enabled/disabled if :prop_tgt:`<LANG>_STANDARD` is
+  unset or satisfied by the default.
+
+* Standard mode-affecting flags aren't added unless necessary to achieve the
+  specified mode.
+
+The ``OLD`` behavior:
+
+* Initializes :prop_tgt:`<LANG>_EXTENSIONS` to
+  :variable:`CMAKE_<LANG>_EXTENSIONS` if set, otherwise falling back to ``ON``.
+
+* Always adds a flag if :prop_tgt:`<LANG>_STANDARD` is set and
+  :prop_tgt:`<LANG>_STANDARD_REQUIRED` is ``OFF``.
+
+* If :prop_tgt:`<LANG>_STANDARD` is unset:
+
+  * Doesn't disable extensions even if :prop_tgt:`<LANG>_EXTENSIONS` is
+    ``OFF``.
+
+  * Fails to enable extensions if :prop_tgt:`<LANG>_EXTENSIONS` is ``ON``
+    except for the ``IAR`` compiler.
+
+Code may need to be updated for the ``NEW`` behavior in the following cases:
+
+* If a standard mode flag previously overridden by CMake's and not used during
+  compiler detection now takes effect due to CMake no longer adding one as the
+  default detected is appropriate.
+
+  Such code should be converted to either:
+
+  * Use :prop_tgt:`<LANG>_STANDARD` and :prop_tgt:`<LANG>_EXTENSIONS` instead
+    of manually adding flags.
+
+  * Or ensure the manually-specified flags are used during compiler detection.
+
+* If extensions were disabled without :prop_tgt:`<LANG>_STANDARD` being set
+  CMake previously wouldn't actually disable extensions.
+
+  Such code should be updated to not disable extensions if they are required.
+
+* If extensions were enabled/disabled when :prop_tgt:`<LANG>_STANDARD` was
+  satisfied by the compiler's default CMake previously wouldn't actually
+  enable/disable extensions.
+
+  Such code should be updated to set the correct extensions mode.
+
+If compiler flags affecting the standard mode are used during compiler
+detection (for example in :manual:`a toolchain file <cmake-toolchains(7)>`
+using :variable:`CMAKE_<LANG>_FLAGS_INIT`) then they will affect the detected
+default :variable:`standard <CMAKE_<LANG>_STANDARD_DEFAULT>` and
+:variable:`extensions <CMAKE_<LANG>_EXTENSIONS_DEFAULT>`.
+
+Unlike many policies, CMake version |release| does *not* warn when the policy
+is not set and simply uses the ``OLD`` behavior. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0128 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt
index 6bbb870..3a17973 100644 (file)
@@ -32,4 +32,6 @@ The features known to this version of CMake are:
   Compiler mode is at least CUDA/C++ 20.
 
 ``cuda_std_23``
+  .. versionadded:: 3.20
+
   Compiler mode is at least CUDA/C++ 23.
index 73c0b34..1a913fb 100644 (file)
@@ -18,6 +18,8 @@ The features known to this version of CMake are listed below.
 High level meta features indicating C++ standard support
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.8
+
 The following meta features indicate general support for the associated
 language standard.  It reflects the language support claimed by the compiler,
 but it does not necessarily imply complete conformance to that standard.
@@ -35,9 +37,13 @@ but it does not necessarily imply complete conformance to that standard.
   Compiler mode is at least C++ 17.
 
 ``cxx_std_20``
+  .. versionadded:: 3.12
+
   Compiler mode is at least C++ 20.
 
 ``cxx_std_23``
+  .. versionadded:: 3.20
+
   Compiler mode is at least C++ 23.
 
 Low level individual compile features
index 2bd0feb..97da697 100644 (file)
@@ -13,7 +13,12 @@ The features listed here may be used with the :command:`target_compile_features`
 command.  See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
 
-The features known to this version of CMake are:
+The features known to this version of CMake are listed below.
+
+High level meta features indicating C standard support
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.8
 
 ``c_std_90``
   Compiler mode is at least C 90.
@@ -25,11 +30,18 @@ The features known to this version of CMake are:
   Compiler mode is at least C 11.
 
 ``c_std_17``
+  .. versionadded:: 3.21
+
   Compiler mode is at least C 17.
 
 ``c_std_23``
+  .. versionadded:: 3.21
+
   Compiler mode is at least C 23.
 
+Low level individual compile features
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 ``c_function_prototypes``
   Function prototypes, as defined in ``ISO/IEC 9899:1990``.
 
index 322f5a6..871e36e 100644 (file)
@@ -3,7 +3,12 @@ VS_SETTINGS
 
 .. versionadded:: 3.18
 
-Set any item metadata on a non-built file.
+Set any item metadata on a file.
+
+.. versionadded:: 3.22
+
+  This property is honored for all source file types.
+  Previously it worked only for non-built files.
 
 Takes a list of ``Key=Value`` pairs. Tells the Visual Studio generator to set
 ``Key`` to ``Value`` as item metadata on the file.
index 102c792..43bcdbe 100644 (file)
@@ -5,5 +5,5 @@ Specify environment variables that should be defined for running a test.
 
 If set to a list of environment variables and values of the form
 ``MYVAR=value`` those environment variables will be defined while running
-the test.  The environment is restored to its previous state after the
-test is done.
+the test.  The environment changes from this property do not affect other
+tests.
diff --git a/Help/prop_test/ENVIRONMENT_MODIFICATION.rst b/Help/prop_test/ENVIRONMENT_MODIFICATION.rst
new file mode 100644 (file)
index 0000000..0b3cd83
--- /dev/null
@@ -0,0 +1,36 @@
+ENVIRONMENT_MODIFICATION
+------------------------
+
+.. versionadded:: 3.22
+
+Specify environment variables that should be modified for running a test. Note
+that the operations performed by this property are performed after the
+:prop_test:`ENVIRONMENT` property is already applied.
+
+If set to a list of environment variables and values of the form
+``MYVAR=OP:VALUE``, where ``MYVAR`` is the case-sensitive name of an
+environment variable to be modified. Entries are considered in the
+order specified in the property's value. The ``OP`` may be one of:
+
+  - ``reset``: Reset to the unmodified value, ignoring all modifications to
+    ``MYVAR`` prior to this entry. Note that this will reset the variable to
+    the value set by :prop_test:`ENVIRONMENT`, if it was set, and otherwise
+    to its state from the rest of the CTest execution.
+  - ``set``: Replaces the current value of ``MYVAR`` with ``VALUE``.
+  - ``unset``: Unsets the current value of ``MYVAR``.
+  - ``string_append``: Appends ``VALUE`` to the current value of ``MYVAR``.
+  - ``string_prepend``: Prepends ``VALUE`` to the current value of ``MYVAR``.
+  - ``path_list_append``: Appends ``VALUE`` to the current value of ``MYVAR``
+    using the platform-specific list separator.
+  - ``path_list_prepend``: Prepends ``VALUE`` to the current value of
+    ``MYVAR`` using the platform-specific list separator.
+  - ``cmake_list_append``: Appends ``VALUE`` to the current value of ``MYVAR``
+    using ``;`` as the separator.
+  - ``cmake_list_prepend``: Prepends ``VALUE`` to the current value of
+    ``MYVAR`` using ``;`` as the separator.
+
+Unrecognized ``OP`` values will result in the test failing before it is
+executed. This is so that future operations may be added without changing
+valid behavior of existing tests.
+
+The environment changes from this property do not affect other tests.
index 8d75570..a06f152 100644 (file)
@@ -1,6 +1,10 @@
 LABELS
 ------
 
-Specify a list of text labels associated with a test.
+Specify a list of text labels associated with a test.  The labels are
+reported in both the ``ctest`` output summary and in dashboard submissions.
+They can also be used to filter the set of tests to be executed (see the
+``ctest -L`` and ``ctest -LE`` :ref:`CTest Options`).
 
-The list is reported in dashboard submissions.
+See :ref:`Additional Labels` for adding labels to a test dynamically during
+test execution.
index 52d96e0..ed8b262 100644 (file)
@@ -4,9 +4,9 @@ AUTOMOC
 Should the target be processed with auto-moc (for Qt projects).
 
 :prop_tgt:`AUTOMOC` is a boolean specifying whether CMake will handle the Qt
-``moc`` preprocessor automatically, i.e.  without having to use the
-:module:`QT4_WRAP_CPP() <FindQt4>` or ``QT5_WRAP_CPP()`` macro.
-Currently Qt4 and Qt5 are supported.
+``moc`` preprocessor automatically, i.e.  without having to use commands like
+:module:`QT4_WRAP_CPP() <FindQt4>`, ``QT5_WRAP_CPP()``, etc.
+Currently, Qt versions 4 to 6 are supported.
 
 This property is initialized by the value of the :variable:`CMAKE_AUTOMOC`
 variable if it is set when a target is created.
@@ -148,10 +148,13 @@ Qt version detection
 
 :prop_tgt:`AUTOMOC` enabled targets need to know the Qt major and minor
 version they're working with.  The major version usually is provided by the
-``INTERFACE_QT_MAJOR_VERSION`` property of the ``Qt[45]Core`` library,
+``INTERFACE_QT_MAJOR_VERSION`` property of the ``Qt[456]Core`` library,
 that the target links to.  To find the minor version, CMake builds a list of
 available Qt versions from
 
+- ``Qt6Core_VERSION_MAJOR`` and ``Qt6Core_VERSION_MINOR`` variables
+  (usually set by ``find_package(Qt6...)``)
+- ``Qt6Core_VERSION_MAJOR`` and ``Qt6Core_VERSION_MINOR`` directory properties
 - ``Qt5Core_VERSION_MAJOR`` and ``Qt5Core_VERSION_MINOR`` variables
   (usually set by ``find_package(Qt5...)``)
 - ``Qt5Core_VERSION_MAJOR`` and ``Qt5Core_VERSION_MINOR`` directory properties
@@ -167,13 +170,13 @@ version was found, an error is generated.
 If  ``INTERFACE_QT_MAJOR_VERSION`` is not a valid number, the first
 entry in the list is taken.
 
-A ``find_package(Qt[45]...)`` call sets the ``QT/Qt5Core_VERSION_MAJOR/MINOR``
+A ``find_package(Qt[456]...)`` call sets the ``QT/Qt[56]Core_VERSION_MAJOR/MINOR``
 variables.  If the call is in a different context than the
 :command:`add_executable` or :command:`add_library` call, e.g. in a function,
 then the version variables might not be available to the :prop_tgt:`AUTOMOC`
 enabled target.
 In that case the version variables can be forwarded from the
-``find_package(Qt[45]...)`` calling context to the :command:`add_executable`
+``find_package(Qt[456]...)`` calling context to the :command:`add_executable`
 or :command:`add_library` calling context as directory properties.
 The following Qt5 example demonstrates the procedure.
 
index 9a98f44..0a0c2a1 100644 (file)
@@ -5,8 +5,8 @@ Should the target be processed with auto-rcc (for Qt projects).
 
 :prop_tgt:`AUTORCC` is a boolean specifying whether CMake will handle
 the Qt ``rcc`` code generator automatically, i.e. without having to use
-the :module:`QT4_ADD_RESOURCES() <FindQt4>` or ``QT5_ADD_RESOURCES()``
-macro.  Currently Qt4 and Qt5 are supported.
+commands like :module:`QT4_ADD_RESOURCES() <FindQt4>`, ``QT5_ADD_RESOURCES()``,
+etc.  Currently, Qt versions 4 to 6 are supported.
 
 When this property is ``ON``, CMake will handle ``.qrc`` files added
 as target sources at build time and invoke ``rcc`` accordingly.
index cd24f5e..e0cea97 100644 (file)
@@ -5,8 +5,8 @@ Should the target be processed with auto-uic (for Qt projects).
 
 :prop_tgt:`AUTOUIC` is a boolean specifying whether CMake will handle
 the Qt ``uic`` code generator automatically, i.e. without having to use
-the :module:`QT4_WRAP_UI() <FindQt4>` or ``QT5_WRAP_UI()`` macro. Currently
-Qt4 and Qt5 are supported.
+commands like :module:`QT4_WRAP_UI() <FindQt4>`, ``QT5_WRAP_UI()``, etc.
+Currently, Qt versions 4 to 6 are supported.
 
 This property is initialized by the value of the :variable:`CMAKE_AUTOUIC`
 variable if it is set when a target is created.
index 2ddba0b..ab467ac 100644 (file)
@@ -15,5 +15,7 @@ See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
 
 This property is initialized by the value of
-the :variable:`CMAKE_CUDA_EXTENSIONS` variable if it is set when a target
-is created.
+the :variable:`CMAKE_CUDA_EXTENSIONS` variable if set when a target is created
+and otherwise by the value of
+:variable:`CMAKE_CUDA_EXTENSIONS_DEFAULT <CMAKE_<LANG>_EXTENSIONS_DEFAULT>`
+(see :policy:`CMP0128`).
index 5ef57be..950ba12 100644 (file)
@@ -12,21 +12,27 @@ flag such as ``-std=gnu++11`` to the compile line.
 Supported values are:
 
 ``98``
-  CUDA C++98
+  CUDA C++98. Note that this maps to the same as ``03`` internally.
+
+``03``
+  CUDA C++03
 
 ``11``
   CUDA C++11
 
 ``14``
-  CUDA C++14
+  CUDA C++14. While CMake 3.8 and later *recognize* ``14`` as a valid value,
+  CMake 3.9 was the first version to include support for any compiler.
 
 ``17``
-  CUDA C++17
+  CUDA C++17. While CMake 3.8 and later *recognize* ``17`` as a valid value,
+  CMake 3.18 was the first version to include support for any compiler.
 
 ``20``
   .. versionadded:: 3.12
 
-  CUDA C++20
+  CUDA C++20. While CMake 3.12 and later *recognize* ``20`` as a valid value,
+  CMake 3.18 was the first version to include support for any compiler.
 
 ``23``
   .. versionadded:: 3.20
@@ -43,7 +49,7 @@ means that using:
 
 with a compiler which does not support ``-std=gnu++11`` or an equivalent
 flag will not result in an error or warning, but will instead add the
-``-std=gnu++98`` flag if supported.  This "decay" behavior may be controlled
+``-std=gnu++03`` flag if supported.  This "decay" behavior may be controlled
 with the :prop_tgt:`CUDA_STANDARD_REQUIRED` target property.
 Additionally, the :prop_tgt:`CUDA_EXTENSIONS` target property may be used to
 control whether compiler-specific extensions are enabled on a per-target basis.
index bda531e..9b52504 100644 (file)
@@ -15,5 +15,7 @@ See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
 
 This property is initialized by the value of
-the :variable:`CMAKE_CXX_EXTENSIONS` variable if it is set when a target
-is created.
+the :variable:`CMAKE_CXX_EXTENSIONS` variable if set when a target is created
+and otherwise by the value of
+:variable:`CMAKE_CXX_EXTENSIONS_DEFAULT <CMAKE_<LANG>_EXTENSIONS_DEFAULT>` (see
+:policy:`CMP0128`).
index b2abb46..a53090c 100644 (file)
@@ -15,5 +15,7 @@ See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
 
 This property is initialized by the value of
-the :variable:`CMAKE_C_EXTENSIONS` variable if it is set when a target
-is created.
+the :variable:`CMAKE_C_EXTENSIONS` variable if set when a target is created and
+otherwise by the value of
+:variable:`CMAKE_C_EXTENSIONS_DEFAULT <CMAKE_<LANG>_EXTENSIONS_DEFAULT>` (see
+:policy:`CMP0128`).
diff --git a/Help/prop_tgt/Fortran_BUILDING_INSTRINSIC_MODULES.rst b/Help/prop_tgt/Fortran_BUILDING_INSTRINSIC_MODULES.rst
new file mode 100644 (file)
index 0000000..3533ef9
--- /dev/null
@@ -0,0 +1,16 @@
+Fortran_BUILDING_INSTRINSIC_MODULES
+-----------------------------------
+
+.. versionadded:: 3.22
+
+Instructs the CMake Fortran preprocessor that the target is building
+Fortran intrinsics for building a Fortran compiler.
+
+This property is off by default and should be turned only on projects
+that build a Fortran compiler. It should not be turned on for projects
+that use a Fortran compiler.
+
+Turning this property on will correctly add dependencies for building
+Fortran intrinsic modules whereas turning the property off will ignore
+Fortran intrinsic modules in the dependency graph as they are supplied
+by the compiler itself.
diff --git a/Help/prop_tgt/HIP_EXTENSIONS.rst b/Help/prop_tgt/HIP_EXTENSIONS.rst
new file mode 100644 (file)
index 0000000..d1475c9
--- /dev/null
@@ -0,0 +1,21 @@
+HIP_EXTENSIONS
+--------------
+
+.. versionadded:: 3.21
+
+Boolean specifying whether compiler specific extensions are requested.
+
+This property specifies whether compiler specific extensions should be
+used.  For some compilers, this results in adding a flag such
+as ``-std=gnu++11`` instead of ``-std=c++11`` to the compile line.  This
+property is ``ON`` by default. The basic HIP/C++ standard level is
+controlled by the :prop_tgt:`HIP_STANDARD` target property.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_HIP_EXTENSIONS` variable if set when a target is created
+and otherwise by the value of
+:variable:`CMAKE_HIP_EXTENSIONS_DEFAULT <CMAKE_<LANG>_EXTENSIONS_DEFAULT>` (see
+:policy:`CMP0128`).
diff --git a/Help/prop_tgt/HIP_STANDARD.rst b/Help/prop_tgt/HIP_STANDARD.rst
new file mode 100644 (file)
index 0000000..0c767c6
--- /dev/null
@@ -0,0 +1,48 @@
+HIP_STANDARD
+------------
+
+.. versionadded:: 3.21
+
+The HIP/C++ standard requested to build this target.
+
+Supported values are:
+
+``98``
+  HIP C++98
+
+``11``
+  HIP C++11
+
+``14``
+  HIP C++14
+
+``17``
+  HIP C++17
+
+``20``
+  HIP C++20
+
+``23``
+  HIP C++23
+
+If the value requested does not result in a compile flag being added for
+the compiler in use, a previous standard flag will be added instead.  This
+means that using:
+
+.. code-block:: cmake
+
+  set_property(TARGET tgt PROPERTY HIP_STANDARD 11)
+
+with a compiler which does not support ``-std=gnu++11`` or an equivalent
+flag will not result in an error or warning, but will instead add the
+``-std=gnu++98`` flag if supported.  This "decay" behavior may be controlled
+with the :prop_tgt:`HIP_STANDARD_REQUIRED` target property.
+Additionally, the :prop_tgt:`HIP_EXTENSIONS` target property may be used to
+control whether compiler-specific extensions are enabled on a per-target basis.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_HIP_STANDARD` variable if it is set when a target
+is created.
diff --git a/Help/prop_tgt/HIP_STANDARD_REQUIRED.rst b/Help/prop_tgt/HIP_STANDARD_REQUIRED.rst
new file mode 100644 (file)
index 0000000..e56209a
--- /dev/null
@@ -0,0 +1,19 @@
+HIP_STANDARD_REQUIRED
+---------------------
+
+.. versionadded:: 3.21
+
+Boolean describing whether the value of :prop_tgt:`HIP_STANDARD` is a requirement.
+
+If this property is set to ``ON``, then the value of the
+:prop_tgt:`HIP_STANDARD` target property is treated as a requirement.  If this
+property is ``OFF`` or unset, the :prop_tgt:`HIP_STANDARD` target property is
+treated as optional and may "decay" to a previous standard if the requested is
+not available.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+This property is initialized by the value of
+the :variable:`CMAKE_HIP_STANDARD_REQUIRED` variable if it is set when a
+target is created.
diff --git a/Help/prop_tgt/LANG_EXTENSIONS.rst b/Help/prop_tgt/LANG_EXTENSIONS.rst
new file mode 100644 (file)
index 0000000..afc2ad3
--- /dev/null
@@ -0,0 +1,24 @@
+<LANG>_EXTENSIONS
+-----------------
+
+The variations are:
+
+* :prop_tgt:`C_EXTENSIONS`
+* :prop_tgt:`CXX_EXTENSIONS`
+* :prop_tgt:`CUDA_EXTENSIONS`
+* :prop_tgt:`HIP_EXTENSIONS`
+* :prop_tgt:`OBJC_EXTENSIONS`
+* :prop_tgt:`OBJCXX_EXTENSIONS`
+
+These properties specify whether compiler-specific extensions are requested.
+
+These properties are initialized by the value of the
+:variable:`CMAKE_<LANG>_EXTENSIONS` variable if it is set when a target is
+created and otherwise by the value of
+:variable:`CMAKE_<LANG>_EXTENSIONS_DEFAULT` (see :policy:`CMP0128`).
+
+For supported CMake versions see the respective pages.
+To control language standard versions see :prop_tgt:`<LANG>_STANDARD`.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/prop_tgt/LANG_STANDARD.rst b/Help/prop_tgt/LANG_STANDARD.rst
new file mode 100644 (file)
index 0000000..bd377ec
--- /dev/null
@@ -0,0 +1,26 @@
+<LANG>_STANDARD
+---------------
+
+The variations are:
+
+* :prop_tgt:`C_STANDARD`
+* :prop_tgt:`CXX_STANDARD`
+* :prop_tgt:`CUDA_STANDARD`
+* :prop_tgt:`HIP_STANDARD`
+* :prop_tgt:`OBJC_STANDARD`
+* :prop_tgt:`OBJCXX_STANDARD`
+
+These properties specify language standard versions which are requested. When a
+newer standard is specified than is supported by the compiler, then it will
+fallback to the latest supported standard. This "decay" behavior may be
+controlled with the :prop_tgt:`<LANG>_STANDARD_REQUIRED` target property.
+
+These properties are initialized by the value of the
+:variable:`CMAKE_<LANG>_STANDARD` variable if it is set when a target is
+created.
+
+For supported values and CMake versions see the respective pages.
+To control compiler-specific extensions see :prop_tgt:`<LANG>_EXTENSIONS`.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/prop_tgt/LANG_STANDARD_REQUIRED.rst b/Help/prop_tgt/LANG_STANDARD_REQUIRED.rst
new file mode 100644 (file)
index 0000000..56ecef8
--- /dev/null
@@ -0,0 +1,26 @@
+<LANG>_STANDARD_REQUIRED
+------------------------
+
+The variations are:
+
+* :prop_tgt:`C_STANDARD_REQUIRED`
+* :prop_tgt:`CXX_STANDARD_REQUIRED`
+* :prop_tgt:`CUDA_STANDARD_REQUIRED`
+* :prop_tgt:`HIP_STANDARD_REQUIRED`
+* :prop_tgt:`OBJC_STANDARD_REQUIRED`
+* :prop_tgt:`OBJCXX_STANDARD_REQUIRED`
+
+These properties specify whether the value of :prop_tgt:`<LANG>_STANDARD` is a
+requirement. When ``OFF`` or unset, the :prop_tgt:`<LANG>_STANDARD` target
+property is treated as optional and may "decay" to a previous standard if the
+requested is not available.
+
+These properties are initialized by the value of the
+:variable:`CMAKE_<LANG>_STANDARD_REQUIRED` variable if it is set when a target
+is created.
+
+For supported CMake versions see the respective pages.
+To control language standard versions see :prop_tgt:`<LANG>_STANDARD`.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
index 2ed93ad..d6de0d4 100644 (file)
@@ -1,16 +1,22 @@
 LINK_WHAT_YOU_USE
----------------------------
+-----------------
 
 .. versionadded:: 3.7
 
-This is a boolean option that when set to ``TRUE`` will automatically run
-``ldd -r -u`` on the target after it is linked. In addition, the linker flag
-``-Wl,--no-as-needed`` will be passed to the target with the link command so
-that all libraries specified on the command line will be linked into the
-target. This will result in the link producing a list of libraries that
-provide no symbols used by this target but are being linked to it.
-This is only applicable to executable and shared library targets and
-will only work when ld and ldd accept the flags used.
+This is a boolean option that, when set to ``TRUE``, will automatically run
+contents of variable :variable:`CMAKE_LINK_WHAT_YOU_USE_CHECK` on the target
+after it is linked. In addition, the linker flag specified by variable
+:variable:`CMAKE_<LANG>_LINK_WHAT_YOU_USE_FLAG`  will be passed to the target
+with the link command so that all libraries specified on the command line will
+be linked into the target. This will result in the link producing a list of
+libraries that provide no symbols used by this target but are being linked to
+it.
+
+.. note::
+
+  For now, it is only supported for ``ELF`` platforms and is only applicable to
+  executable and shared or module library targets. This property will be
+  ignored for any other targets and configurations.
 
 This property is initialized by the value of
 the :variable:`CMAKE_LINK_WHAT_YOU_USE` variable if it is set
index 8a254f2..2a15dec 100644 (file)
@@ -18,5 +18,7 @@ If the property is not set, and the project has set the :prop_tgt:`CXX_EXTENSION
 the value of :prop_tgt:`CXX_EXTENSIONS` is set for :prop_tgt:`OBJCXX_EXTENSIONS`.
 
 This property is initialized by the value of
-the :variable:`CMAKE_OBJCXX_EXTENSIONS` variable if it is set when a target
-is created.
+the :variable:`CMAKE_OBJCXX_EXTENSIONS` variable if set when a target is
+created and otherwise by the value of
+:variable:`CMAKE_OBJCXX_EXTENSIONS_DEFAULT <CMAKE_<LANG>_EXTENSIONS_DEFAULT>`
+(see :policy:`CMP0128`).
index ef1c754..cd72e5f 100644 (file)
@@ -18,5 +18,7 @@ See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
 
 This property is initialized by the value of
-the :variable:`CMAKE_OBJC_EXTENSIONS` variable if it is set when a target
-is created.
+the :variable:`CMAKE_OBJC_EXTENSIONS` variable if set when a target is created
+and otherwise by the value of
+:variable:`CMAKE_OBJC_EXTENSIONS_DEFAULT <CMAKE_<LANG>_EXTENSIONS_DEFAULT>`
+(see :policy:`CMP0128`).
index 462d2be..e1c6172 100644 (file)
@@ -334,10 +334,3 @@ Changes made since CMake 3.21.0 include the following.
 * The :generator:`Visual Studio 17 2022` generator is now based on the
   "Visual Studio 2022" release candidates.  Previously it was based on
   preview versions.
-
-3.21.5, 3.21.6, 3.21.7
-----------------------
-
-These versions made no changes to documented features or interfaces.
-Some implementation updates were made to support ecosystem changes
-and/or fix regressions.
diff --git a/Help/release/3.22.rst b/Help/release/3.22.rst
new file mode 100644 (file)
index 0000000..fcb655d
--- /dev/null
@@ -0,0 +1,144 @@
+CMake 3.22 Release Notes
+************************
+
+.. only:: html
+
+  .. contents::
+
+Changes made since CMake 3.21 include the following.
+
+New Features
+============
+
+Commands
+--------
+
+* The :command:`cmake_host_system_information` command can now query
+  `OS identification variables`_ from the :file:`/etc/os-release` file.
+
+* The :command:`string(TIMESTAMP)` command now supports the ``%V``
+  specifier for ISO 8601 week numbers.
+
+.. _`OS identification variables`: https://www.freedesktop.org/software/systemd/man/os-release.html
+
+Variables
+---------
+
+* The :envvar:`CMAKE_BUILD_TYPE` environment variable was added to
+  provide a default value for the :variable:`CMAKE_BUILD_TYPE` variable.
+
+* The :envvar:`CMAKE_CONFIGURATION_TYPES` environment variable was added to
+  provide a default value for the :variable:`CMAKE_CONFIGURATION_TYPES`
+  variable.
+
+* The :envvar:`CMAKE_INSTALL_MODE` environment variable was added to
+  tell :command:`install` rules (implemented by :command:`file(INSTALL)`)
+  to install symbolic links instead of copying of files.
+
+* The :variable:`CMAKE_<LANG>_LINK_WHAT_YOU_USE_FLAG` and
+  :variable:`CMAKE_LINK_WHAT_YOU_USE_CHECK` variables were added to
+  control the linker flag and check used by the
+  :prop_tgt:`LINK_WHAT_YOU_USE` target property.
+
+* The :variable:`CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>` variable
+  was added to turn a non-REQUIRED :command:`find_package` call into
+  a REQUIRED one.
+
+Properties
+----------
+
+* The :prop_tgt:`<LANG>_EXTENSIONS` target property is now initialized to
+  :variable:`CMAKE_<LANG>_EXTENSIONS_DEFAULT`, detected from the compiler.
+  See :policy:`CMP0128`.
+
+* The :prop_sf:`VS_SETTINGS` source file property is now supported for
+  all source file types.  Previously it worked only for non-built sources.
+
+Modules
+-------
+
+* The :module:`CMakeDependentOption` module :command:`cmake_dependent_option`
+  macro now supports full :ref:`Condition Syntax`.
+  See policy :policy:`CMP0127`.
+
+* The :module:`FetchContent` module now passes through the
+  :variable:`CMAKE_TLS_VERIFY`, :variable:`CMAKE_TLS_CAINFO`,
+  :variable:`CMAKE_NETRC` and :variable:`CMAKE_NETRC_FILE` variables (when
+  defined) to the underlying :module:`ExternalProject` sub-build.
+  Previously, those variables were silently ignored by :module:`FetchContent`.
+
+* The :module:`FindBLAS` and :module:`FindLAPACK` modules gained
+  a ``BLA_SIZEOF_INTEGER`` option to find a BLAS/LAPACK whose ABI
+  uses a specific integer size.
+
+* The :module:`FindJasper` module now provides an imported target.
+
+* The :module:`FindMatlab` module now provides imported targets.
+
+* The :module:`FindPkgConfig` module gained a :variable:`PKG_CONFIG_ARGN`
+  variable to specify arguments to ``pkg-config`` calls.
+
+* The :module:`GoogleTest` module :command:`gtest_discover_tests`
+  function gained a ``TEST_FILTER`` option to filter tests using
+  ``--gtest_filter`` during test discovery.
+
+* The :module:`UseSWIG` module, for :ref:`Visual Studio Generators`,
+  can now use the ``swig`` tool to generate implicit dependencies.
+
+CTest
+-----
+
+* :manual:`ctest(1)` learned to recognize labels attached to a test at run time.
+  Previously it was only possible to attach labels to tests at configure time
+  by using the :prop_test:`LABELS` test property.
+  See :ref:`Additional Test Measurements` for more information.
+
+* :manual:`ctest(1)` learned to be able to modify the environment for a test
+  through the :prop_test:`ENVIRONMENT_MODIFICATION` property. This is allows
+  for updates to environment variables based on the environment present at
+  test time.
+
+* The :command:`ctest_memcheck` command now also generates a
+  :file:`DynamicAnalysis-Test.xml` file which may be used to submit test
+  results to CDash.
+
+CPack
+-----
+
+* The :cpack_gen:`CPack DEB Generator` gained the
+  option to set :variable:`CPACK_DEBIAN_COMPRESSION_TYPE` to ``zstd``,
+  which enables Zstandard compression for deb packages.
+
+* The :cpack_gen:`CPack NSIS Generator` gained a new
+  :variable:`CPACK_NSIS_IGNORE_LICENSE_PAGE` variable to suppress
+  the license page in the installer.
+
+* The :cpack_gen:`CPack RPM Generator` gained the
+  :variable:`CPACK_RPM_REQUIRES_EXCLUDE_FROM` option to avoid scanning
+  specific paths for dependencies.
+
+Deprecated and Removed Features
+===============================
+
+* The :generator:`Visual Studio 10 2010` generator is now deprecated
+  and will be removed in a future version of CMake.
+
+Other Changes
+=============
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality now
+  correctly disables or enables compiler extensions when no standard level is
+  specified and avoids unnecessarily adding language standard flags if the
+  requested settings match the compiler's defaults. See :policy:`CMP0128`.
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+  now ignores features for languages that are not enabled.
+
+* The :ref:`Ninja Generators` now implement the ``edit_cache`` target
+  using :manual:`ccmake(1)` if available.
+
+* The :generator:`Ninja` and :generator:`NMake Makefiles` generators
+  now use the MSVC ``-external:I`` flag for system includes.
+  This became available as of VS 16.10 (toolchain version 14.29.30037).
+
+* The :cpack_gen:`CPack NSIS Generator` now requires NSIS 3.03 or later.
index 75667e5..3d2ed43 100644 (file)
@@ -13,6 +13,7 @@ Releases
 .. toctree::
    :maxdepth: 1
 
+   3.22 <3.22>
    3.21 <3.21>
    3.20 <3.20>
    3.19 <3.19>
index 405f7d5..bb95436 100644 (file)
@@ -1,25 +1,21 @@
 CMAKE_BUILD_TYPE
 ----------------
 
-Specifies the build type on single-configuration generators.
+Specifies the build type on single-configuration generators (e.g.
+:ref:`Makefile Generators` or :generator:`Ninja`).  Typical values include
+``Debug``, ``Release``, ``RelWithDebInfo`` and ``MinSizeRel``, but custom
+build types can also be defined.
 
-This statically specifies what build type (configuration) will be
-built in this build tree.  Possible values are empty, ``Debug``, ``Release``,
-``RelWithDebInfo``, ``MinSizeRel``, ...  This variable is only meaningful to
-single-configuration generators (such as :ref:`Makefile Generators` and
-:generator:`Ninja`) i.e.  those which choose a single configuration when CMake
-runs to generate a build tree as opposed to multi-configuration generators
-which offer selection of the build configuration within the generated build
-environment.  There are many per-config properties and variables
-(usually following clean ``SOME_VAR_<CONFIG>`` order conventions), such as
-``CMAKE_C_FLAGS_<CONFIG>``, specified as uppercase:
-``CMAKE_C_FLAGS_[DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL|...]``.  For example,
-in a build tree configured to build type ``Debug``, CMake will see to
-having :variable:`CMAKE_C_FLAGS_DEBUG <CMAKE_<LANG>_FLAGS_DEBUG>` settings get
-added to the :variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>` settings.  See
-also :variable:`CMAKE_CONFIGURATION_TYPES`.
+This variable is initialized by the first :command:`project` or
+:command:`enable_language` command called in a project when a new build
+tree is first created.  If the :envvar:`CMAKE_BUILD_TYPE` environment
+variable is set, its value is used.  Otherwise, a toolchain-specific
+default is chosen when a language is enabled.  The default value is often
+an empty string, but this is usually not desirable and one of the other
+standard build types is usually more appropriate.
 
-Note that configuration names are case-insensitive.  The value of this
-variable will be the same as it is specified when invoking CMake.
-For instance, if ``-DCMAKE_BUILD_TYPE=ReLeAsE`` is specified, then the
-value of ``CMAKE_BUILD_TYPE`` will be ``ReLeAsE``.
+Depending on the situation, the value of this variable may be treated
+case-sensitively or case-insensitively.  See :ref:`Build Configurations`
+for discussion of this and other related topics.
+
+For multi-config generators, see :variable:`CMAKE_CONFIGURATION_TYPES`.
index 8fcc798..75ff8a1 100644 (file)
@@ -1,12 +1,20 @@
 CMAKE_CONFIGURATION_TYPES
 -------------------------
 
-Specifies the available build types on multi-config generators.
+Specifies the available build types (configurations) on multi-config
+generators (e.g. :ref:`Visual Studio <Visual Studio Generators>`,
+:generator:`Xcode`, or :generator:`Ninja Multi-Config`).  Typical values
+include ``Debug``, ``Release``, ``RelWithDebInfo`` and ``MinSizeRel``,
+but custom build types can also be defined.
 
-This specifies what build types (configurations) will be available
-such as ``Debug``, ``Release``, ``RelWithDebInfo`` etc.  This has reasonable
-defaults on most platforms, but can be extended to provide other build
-types.
+This variable is initialized by the first :command:`project` or
+:command:`enable_language` command called in a project when a new build
+tree is first created.  If the :envvar:`CMAKE_CONFIGURATION_TYPES`
+environment variable is set, its value is used.  Otherwise, the default
+value is generator-specific.
 
-See :variable:`CMAKE_BUILD_TYPE` for specifying the configuration with
-single-config generators.
+Depending on the situation, the values in this variable may be treated
+case-sensitively or case-insensitively.  See :ref:`Build Configurations`
+for discussion of this and other related topics.
+
+For single-config generators, see :variable:`CMAKE_BUILD_TYPE`.
index b86c0ea..12749ce 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_CUDA_EXTENSIONS
 
 .. versionadded:: 3.8
 
-Default value for :prop_tgt:`CUDA_EXTENSIONS` property of targets.
-
-This variable is used to initialize the :prop_tgt:`CUDA_EXTENSIONS`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`CUDA_EXTENSIONS` target property if set when a
+target is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index 798ab1e..ee9395a 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_CUDA_STANDARD
 
 .. versionadded:: 3.8
 
-Default value for :prop_tgt:`CUDA_STANDARD` property of targets.
-
-This variable is used to initialize the :prop_tgt:`CUDA_STANDARD`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`CUDA_STANDARD` target property if set when a
+target is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index ae2f52f..0c85a04 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_CUDA_STANDARD_REQUIRED
 
 .. versionadded:: 3.8
 
-Default value for :prop_tgt:`CUDA_STANDARD_REQUIRED` property of targets.
-
-This variable is used to initialize the :prop_tgt:`CUDA_STANDARD_REQUIRED`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`CUDA_STANDARD_REQUIRED` target property if set
+when a target is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index ea8c4be..017f503 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_CXX_EXTENSIONS
 
 .. versionadded:: 3.1
 
-Default value for :prop_tgt:`CXX_EXTENSIONS` property of targets.
-
-This variable is used to initialize the :prop_tgt:`CXX_EXTENSIONS`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`CXX_EXTENSIONS` target property if set when a
+target is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index 8ef8c80..33eb89e 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_CXX_STANDARD
 
 .. versionadded:: 3.1
 
-Default value for :prop_tgt:`CXX_STANDARD` property of targets.
-
-This variable is used to initialize the :prop_tgt:`CXX_STANDARD`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`CXX_STANDARD` target property if set when a target
+is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index f7b2ae9..1c6c0cc 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_CXX_STANDARD_REQUIRED
 
 .. versionadded:: 3.1
 
-Default value for :prop_tgt:`CXX_STANDARD_REQUIRED` property of targets.
-
-This variable is used to initialize the :prop_tgt:`CXX_STANDARD_REQUIRED`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`CXX_STANDARD_REQUIRED` target property if set when
+a target is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index fce8fc7..6680521 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_C_EXTENSIONS
 
 .. versionadded:: 3.1
 
-Default value for :prop_tgt:`C_EXTENSIONS` property of targets.
-
-This variable is used to initialize the :prop_tgt:`C_EXTENSIONS`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`C_EXTENSIONS` target property if set when a target
+is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index 64ef8ce..ec1e513 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_C_STANDARD
 
 .. versionadded:: 3.1
 
-Default value for :prop_tgt:`C_STANDARD` property of targets.
-
-This variable is used to initialize the :prop_tgt:`C_STANDARD`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`C_STANDARD` target property if set when a target
+is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index e70b6bd..2bd9d51 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_C_STANDARD_REQUIRED
 
 .. versionadded:: 3.1
 
-Default value for :prop_tgt:`C_STANDARD_REQUIRED` property of targets.
-
-This variable is used to initialize the :prop_tgt:`C_STANDARD_REQUIRED`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`C_STANDARD_REQUIRED` target property if set when
+a target is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index ed60020..f77e939 100644 (file)
@@ -14,3 +14,5 @@ the package has already been found in a previous CMake run, the
 variables which have been stored in the cache will still be there.  In
 that case it is recommended to remove the cache variables for this
 package from the cache using the cache editor or :manual:`cmake(1)` ``-U``
+
+See also the :variable:`CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>` variable.
index 4a64e33..c2c2609 100644 (file)
@@ -5,5 +5,8 @@ Suffixes to append when looking for libraries.
 
 This specifies what suffixes to add to library names when the
 :command:`find_library` command looks for libraries.  On Windows systems this
-is typically ``.lib`` and ``.dll``, meaning that when trying to find the
-``foo`` library it will look for ``foo.dll`` etc.
+is typically ``.lib`` and, depending on the compiler, ``.dll.a``, ``.a``
+(e.g. GCC and Clang), so when it tries to find the ``foo`` library, it will
+look for ``[<prefix>]foo.lib`` and/or ``[<prefix>]foo[.dll].a``, depending on
+the compiler used and the ``<prefix>`` specified in the
+:variable:`CMAKE_FIND_LIBRARY_PREFIXES`.
diff --git a/Help/variable/CMAKE_HIP_EXTENSIONS.rst b/Help/variable/CMAKE_HIP_EXTENSIONS.rst
new file mode 100644 (file)
index 0000000..13987dc
--- /dev/null
@@ -0,0 +1,10 @@
+CMAKE_HIP_EXTENSIONS
+--------------------
+
+.. versionadded:: 3.21
+
+Default value for :prop_tgt:`HIP_EXTENSIONS` target property if set when a
+target is created.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_HIP_STANDARD.rst b/Help/variable/CMAKE_HIP_STANDARD.rst
new file mode 100644 (file)
index 0000000..5f15145
--- /dev/null
@@ -0,0 +1,10 @@
+CMAKE_HIP_STANDARD
+------------------
+
+.. versionadded:: 3.21
+
+Default value for :prop_tgt:`HIP_STANDARD` target property if set when a target
+is created.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_HIP_STANDARD_REQUIRED.rst b/Help/variable/CMAKE_HIP_STANDARD_REQUIRED.rst
new file mode 100644 (file)
index 0000000..5d35e4e
--- /dev/null
@@ -0,0 +1,10 @@
+CMAKE_HIP_STANDARD_REQUIRED
+---------------------------
+
+.. versionadded:: 3.21
+
+Default value for :prop_tgt:`HIP_STANDARD_REQUIRED` target property if set when
+a target is created.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_FRONTEND_VARIANT.rst b/Help/variable/CMAKE_LANG_COMPILER_FRONTEND_VARIANT.rst
new file mode 100644 (file)
index 0000000..128b1fb
--- /dev/null
@@ -0,0 +1,18 @@
+CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT
+--------------------------------------
+
+.. versionadded:: 3.14
+
+Identification string of the compiler frontend variant.
+
+Some compilers have multiple, different frontends for accepting command
+line options.  (For example ``Clang`` originally only had a frontend
+compatible with the ``GNU`` compiler but since its port to Windows
+(``Clang-Cl``) it now also supports a frontend compatible with ``MSVC``.)
+When CMake detects such a compiler it sets this
+variable to what would have been the :variable:`CMAKE_<LANG>_COMPILER_ID` for
+the compiler whose frontend it resembles.
+
+.. note::
+  In other words, this variable describes what command line options
+  and language extensions the compiler frontend expects.
diff --git a/Help/variable/CMAKE_LANG_EXTENSIONS.rst b/Help/variable/CMAKE_LANG_EXTENSIONS.rst
new file mode 100644 (file)
index 0000000..3a32002
--- /dev/null
@@ -0,0 +1,20 @@
+CMAKE_<LANG>_EXTENSIONS
+-----------------------
+
+The variations are:
+
+* :variable:`CMAKE_C_EXTENSIONS`
+* :variable:`CMAKE_CXX_EXTENSIONS`
+* :variable:`CMAKE_CUDA_EXTENSIONS`
+* :variable:`CMAKE_HIP_EXTENSIONS`
+* :variable:`CMAKE_OBJC_EXTENSIONS`
+* :variable:`CMAKE_OBJCXX_EXTENSIONS`
+
+Default values for :prop_tgt:`<LANG>_EXTENSIONS` target properties if set when
+a target is created.  For the compiler's default setting see
+:variable:`CMAKE_<LANG>_EXTENSIONS_DEFAULT`.
+
+For supported CMake versions see the respective pages.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_LANG_EXTENSIONS_DEFAULT.rst b/Help/variable/CMAKE_LANG_EXTENSIONS_DEFAULT.rst
new file mode 100644 (file)
index 0000000..a66453a
--- /dev/null
@@ -0,0 +1,10 @@
+CMAKE_<LANG>_EXTENSIONS_DEFAULT
+-------------------------------
+
+.. versionadded:: 3.22
+
+Compiler's default extensions mode. Used as the default for the
+:prop_tgt:`<LANG>_EXTENSIONS` target property when
+:variable:`CMAKE_<LANG>_EXTENSIONS` is not set (see :policy:`CMP0128`).
+
+This variable is read-only.  Modifying it is undefined behavior.
index e9e04be..081c4da 100644 (file)
@@ -6,8 +6,20 @@ Implicit linker search path detected for language ``<LANG>``.
 Compilers typically pass directories containing language runtime
 libraries and default library search paths when they invoke a linker.
 These paths are implicit linker search directories for the compiler's
-language.  CMake automatically detects these directories for each
-language and reports the results in this variable.
+language.  For each language enabled by the :command:`project` or
+:command:`enable_language` command, CMake automatically detects these
+directories and reports the results in this variable.
+
+When linking to a static library, CMake adds the implicit link directories
+from this variable for each language used in the static library (except
+the language whose compiler is used to drive linking).  In the case of an
+imported static library, the :prop_tgt:`IMPORTED_LINK_INTERFACE_LANGUAGES`
+target property lists the languages whose implicit link information is
+needed.  If any of the languages is not enabled, its value for the
+``CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES`` variable may instead be provided
+by the project.  Or, a :variable:`toolchain file <CMAKE_TOOLCHAIN_FILE>`
+may set the variable to a value known for the specified toolchain.  It will
+either be overridden when the language is enabled, or used as a fallback.
 
 Some toolchains read implicit directories from an environment variable such as
 ``LIBRARY_PATH``.  If using such an environment variable, keep its value
@@ -18,3 +30,5 @@ If policy :policy:`CMP0060` is not set to ``NEW``, then when a library in one
 of these directories is given by full path to :command:`target_link_libraries`
 CMake will generate the ``-l<name>`` form on link lines for historical
 purposes.
+
+See also the :variable:`CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES` variable.
index ec16477..0c25489 100644 (file)
@@ -5,6 +5,20 @@ Implicit link libraries and flags detected for language ``<LANG>``.
 
 Compilers typically pass language runtime library names and other
 flags when they invoke a linker.  These flags are implicit link
-options for the compiler's language.  CMake automatically detects
-these libraries and flags for each language and reports the results in
-this variable.
+options for the compiler's language.  For each language enabled
+by the :command:`project` or :command:`enable_language` command,
+CMake automatically detects these libraries and flags and reports
+the results in this variable.
+
+When linking to a static library, CMake adds the implicit link libraries and
+flags from this variable for each language used in the static library (except
+the language whose compiler is used to drive linking).  In the case of an
+imported static library, the :prop_tgt:`IMPORTED_LINK_INTERFACE_LANGUAGES`
+target property lists the languages whose implicit link information is
+needed.  If any of the languages is not enabled, its value for the
+``CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES`` variable may instead be provided
+by the project.  Or, a :variable:`toolchain file <CMAKE_TOOLCHAIN_FILE>`
+may set the variable to a value known for the specified toolchain.  It will
+either be overridden when the language is enabled, or used as a fallback.
+
+See also the :variable:`CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES` variable.
diff --git a/Help/variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG.rst b/Help/variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG.rst
new file mode 100644 (file)
index 0000000..5004530
--- /dev/null
@@ -0,0 +1,9 @@
+CMAKE_<LANG>_LINK_WHAT_YOU_USE_FLAG
+-----------------------------------
+
+.. versionadded:: 3.22
+
+Linker flag to be used to configure linker so that all specified libraries on
+the command line will be linked into the target.
+
+See also variable :variable:`CMAKE_LINK_WHAT_YOU_USE_CHECK`.
index 15c87a1..3226352 100644 (file)
@@ -1,9 +1,13 @@
 CMAKE_<LANG>_SIMULATE_ID
 ------------------------
 
-Identification string of "simulated" compiler.
+Identification string of the "simulated" compiler.
 
 Some compilers simulate other compilers to serve as drop-in
 replacements.  When CMake detects such a compiler it sets this
 variable to what would have been the :variable:`CMAKE_<LANG>_COMPILER_ID` for
 the simulated compiler.
+
+.. note::
+  In other words, this variable describes the ABI compatibility
+  of the generated code.
diff --git a/Help/variable/CMAKE_LANG_STANDARD.rst b/Help/variable/CMAKE_LANG_STANDARD.rst
new file mode 100644 (file)
index 0000000..0c41e19
--- /dev/null
@@ -0,0 +1,19 @@
+CMAKE_<LANG>_STANDARD
+---------------------
+
+The variations are:
+
+* :variable:`CMAKE_C_STANDARD`
+* :variable:`CMAKE_CXX_STANDARD`
+* :variable:`CMAKE_CUDA_STANDARD`
+* :variable:`CMAKE_HIP_STANDARD`
+* :variable:`CMAKE_OBJC_STANDARD`
+* :variable:`CMAKE_OBJCXX_STANDARD`
+
+Default values for :prop_tgt:`<LANG>_STANDARD` target properties if set when a
+target is created.
+
+For supported CMake versions see the respective pages.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_LANG_STANDARD_DEFAULT.rst b/Help/variable/CMAKE_LANG_STANDARD_DEFAULT.rst
new file mode 100644 (file)
index 0000000..eb63d20
--- /dev/null
@@ -0,0 +1,7 @@
+CMAKE_<LANG>_STANDARD_DEFAULT
+-----------------------------
+
+.. versionadded:: 3.9
+
+The compiler's default standard for the language ``<LANG>``. Empty if the
+compiler has no conception of standard levels.
diff --git a/Help/variable/CMAKE_LANG_STANDARD_REQUIRED.rst b/Help/variable/CMAKE_LANG_STANDARD_REQUIRED.rst
new file mode 100644 (file)
index 0000000..d7fa9b6
--- /dev/null
@@ -0,0 +1,19 @@
+CMAKE_<LANG>_STANDARD_REQUIRED
+------------------------------
+
+The variations are:
+
+* :variable:`CMAKE_C_STANDARD_REQUIRED`
+* :variable:`CMAKE_CXX_STANDARD_REQUIRED`
+* :variable:`CMAKE_CUDA_STANDARD_REQUIRED`
+* :variable:`CMAKE_HIP_STANDARD_REQUIRED`
+* :variable:`CMAKE_OBJC_STANDARD_REQUIRED`
+* :variable:`CMAKE_OBJCXX_STANDARD_REQUIRED`
+
+Default values for :prop_tgt:`<LANG>_STANDARD_REQUIRED` target properties if
+set when a target is created.
+
+For supported CMake versions see the respective pages.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
index 06b3aa8..bca4519 100644 (file)
@@ -1,5 +1,5 @@
 CMAKE_LINK_WHAT_YOU_USE
----------------------------------
+-----------------------
 
 .. versionadded:: 3.7
 
diff --git a/Help/variable/CMAKE_LINK_WHAT_YOU_USE_CHECK.rst b/Help/variable/CMAKE_LINK_WHAT_YOU_USE_CHECK.rst
new file mode 100644 (file)
index 0000000..e626641
--- /dev/null
@@ -0,0 +1,10 @@
+CMAKE_LINK_WHAT_YOU_USE_CHECK
+-----------------------------
+
+.. versionadded:: 3.22
+
+Defines the command executed after the link step to check libraries usage.
+This check is currently only defined on ``ELF`` platforms with value
+``ldd -u -r``.
+
+See also :variable:`CMAKE_<LANG>_LINK_WHAT_YOU_USE_FLAG` variables.
index 2c64a81..bddfca5 100644 (file)
@@ -3,9 +3,11 @@ CMAKE_NETRC
 
 .. versionadded:: 3.11
 
-This variable is used to initialize the ``NETRC`` option for
-:command:`file(DOWNLOAD)` and :command:`file(UPLOAD)` commands and the
-module :module:`ExternalProject`. See those commands for additional
-information.
+This variable is used to initialize the ``NETRC`` option for the
+:command:`file(DOWNLOAD)` and :command:`file(UPLOAD)` commands.
+See those commands for additional information.
+
+This variable is also used by the :module:`ExternalProject` and
+:module:`FetchContent` modules for internal calls to :command:`file(DOWNLOAD)`.
 
 The local option takes precedence over this variable.
index 97a645e..af98170 100644 (file)
@@ -3,9 +3,11 @@ CMAKE_NETRC_FILE
 
 .. versionadded:: 3.11
 
-This variable is used to initialize the ``NETRC_FILE`` option for
-:command:`file(DOWNLOAD)` and :command:`file(UPLOAD)` commands and the
-module :module:`ExternalProject`. See those commands for additional
-information.
+This variable is used to initialize the ``NETRC_FILE`` option for the
+:command:`file(DOWNLOAD)` and :command:`file(UPLOAD)` commands.
+See those commands for additional information.
+
+This variable is also used by the :module:`ExternalProject` and
+:module:`FetchContent` modules for internal calls to :command:`file(DOWNLOAD)`.
 
 The local option takes precedence over this variable.
index b5225ea..46736aa 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_OBJCXX_EXTENSIONS
 
 .. versionadded:: 3.16
 
-Default value for :prop_tgt:`OBJCXX_EXTENSIONS` property of targets.
-
-This variable is used to initialize the :prop_tgt:`OBJCXX_EXTENSIONS`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`OBJCXX_EXTENSIONS` target property if set when a
+target is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index 98e4624..0913382 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_OBJCXX_STANDARD
 
 .. versionadded:: 3.16
 
-Default value for :prop_tgt:`OBJCXX_STANDARD` property of targets.
-
-This variable is used to initialize the :prop_tgt:`OBJCXX_STANDARD`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`OBJCXX_STANDARD` target property if set when a
+target is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index 4b5e77c..9afc4ea 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_OBJCXX_STANDARD_REQUIRED
 
 .. versionadded:: 3.16
 
-Default value for :prop_tgt:`OBJCXX_STANDARD_REQUIRED` property of targets.
-
-This variable is used to initialize the :prop_tgt:`OBJCXX_STANDARD_REQUIRED`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`OBJCXX_STANDARD_REQUIRED` target property if set
+when a target is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index d6e3c7d..9df11f1 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_OBJC_EXTENSIONS
 
 .. versionadded:: 3.16
 
-Default value for :prop_tgt:`OBJC_EXTENSIONS` property of targets.
-
-This variable is used to initialize the :prop_tgt:`OBJC_EXTENSIONS`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`OBJC_EXTENSIONS` target property if set when a
+target is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index fde367d..0b9b63f 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_OBJC_STANDARD
 
 .. versionadded:: 3.16
 
-Default value for :prop_tgt:`OBJC_STANDARD` property of targets.
-
-This variable is used to initialize the :prop_tgt:`OBJC_STANDARD`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`OBJC_STANDARD` target property if set when a
+target is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index 8d26d95..c74db55 100644 (file)
@@ -3,11 +3,8 @@ CMAKE_OBJC_STANDARD_REQUIRED
 
 .. versionadded:: 3.16
 
-Default value for :prop_tgt:`OBJC_STANDARD_REQUIRED` property of targets.
-
-This variable is used to initialize the :prop_tgt:`OBJC_STANDARD_REQUIRED`
-property on all targets.  See that target property for additional
-information.
+Default value for :prop_tgt:`OBJC_STANDARD_REQUIRED` target property if set
+when a target is created.
 
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features and a list of supported compilers.
index b991db2..0231668 100644 (file)
@@ -2,8 +2,9 @@ CMAKE_POLICY_WARNING_CMP<NNNN>
 ------------------------------
 
 Explicitly enable or disable the warning when CMake Policy ``CMP<NNNN>``
-is not set.  This is meaningful only for the few policies that do not
-warn by default:
+has not been set explicitly by :command:`cmake_policy` or implicitly
+by :command:`cmake_minimum_required`. This is meaningful
+only for the policies that do not warn by default:
 
 * ``CMAKE_POLICY_WARNING_CMP0025`` controls the warning for
   policy :policy:`CMP0025`.
@@ -31,6 +32,8 @@ warn by default:
   policy :policy:`CMP0116`.
 * ``CMAKE_POLICY_WARNING_CMP0126`` controls the warning for
   policy :policy:`CMP0126`.
+* ``CMAKE_POLICY_WARNING_CMP0128`` controls the warning for
+  policy :policy:`CMP0128`.
 
 This variable should not be set by a project in CMake code.  Project
 developers running CMake may set this variable in their cache to
diff --git a/Help/variable/CMAKE_REQUIRE_FIND_PACKAGE_PackageName.rst b/Help/variable/CMAKE_REQUIRE_FIND_PACKAGE_PackageName.rst
new file mode 100644 (file)
index 0000000..893f1ae
--- /dev/null
@@ -0,0 +1,14 @@
+CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>
+----------------------------------------
+
+.. versionadded:: 3.22
+
+Variable for making :command:`find_package` call ``REQUIRED``.
+
+Every non-``REQUIRED`` :command:`find_package` call in a project can be
+turned into ``REQUIRED`` by setting the variable
+``CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>`` to ``TRUE``.
+This can be used to assert assumptions about build environment and to
+ensure the build will fail early if they do not hold.
+
+See also the :variable:`CMAKE_DISABLE_FIND_PACKAGE_<PackageName>` variable.
diff --git a/Help/variable/CMAKE_TLS_CAINFO.rst b/Help/variable/CMAKE_TLS_CAINFO.rst
new file mode 100644 (file)
index 0000000..07f6366
--- /dev/null
@@ -0,0 +1,9 @@
+CMAKE_TLS_CAINFO
+----------------
+
+Specify the default value for the :command:`file(DOWNLOAD)` and
+:command:`file(UPLOAD)` commands' ``TLS_CAINFO`` options.
+It is unset by default.
+
+This variable is also used by the :module:`ExternalProject` and
+:module:`FetchContent` modules for internal calls to :command:`file(DOWNLOAD)`.
index 24f8a25..b22f1ce 100644 (file)
@@ -5,8 +5,8 @@ Specify the default value for the :command:`file(DOWNLOAD)` and
 :command:`file(UPLOAD)` commands' ``TLS_VERIFY`` options.
 If not set, the default is *off*.
 
-This setting is also used by the :module:`ExternalProject` module
-for internal calls to :command:`file(DOWNLOAD)`.
+This variable is also used by the :module:`ExternalProject` and
+:module:`FetchContent` modules for internal calls to :command:`file(DOWNLOAD)`.
 
 TLS verification can help provide confidence that one is connecting
 to the desired server.  When downloading known content, one should
diff --git a/Help/variable/CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER.rst b/Help/variable/CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER.rst
new file mode 100644 (file)
index 0000000..5ad5897
--- /dev/null
@@ -0,0 +1,13 @@
+CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER
+------------------------------------
+
+.. versionadded:: 3.22
+
+Visual Studio target framework identifier.
+
+In some cases, the :ref:`Visual Studio Generators` may use an explicit value
+for the MSBuild ``TargetFrameworkIdentifier`` setting in ``.csproj`` files.
+CMake provides the chosen value in this variable.
+
+See also :variable:`CMAKE_VS_TARGET_FRAMEWORK_VERSION` and
+:variable:`CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION`.
diff --git a/Help/variable/CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION.rst b/Help/variable/CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION.rst
new file mode 100644 (file)
index 0000000..8dcb3a7
--- /dev/null
@@ -0,0 +1,13 @@
+CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION
+-----------------------------------------
+
+.. versionadded:: 3.22
+
+Visual Studio target framework targets version.
+
+In some cases, the :ref:`Visual Studio Generators` may use an explicit value
+for the MSBuild ``TargetFrameworkTargetsVersion`` setting in ``.csproj`` files.
+CMake provides the chosen value in this variable.
+
+See also :variable:`CMAKE_VS_TARGET_FRAMEWORK_VERSION` and
+:variable:`CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER`.
diff --git a/Help/variable/CMAKE_VS_TARGET_FRAMEWORK_VERSION.rst b/Help/variable/CMAKE_VS_TARGET_FRAMEWORK_VERSION.rst
new file mode 100644 (file)
index 0000000..5489f79
--- /dev/null
@@ -0,0 +1,17 @@
+CMAKE_VS_TARGET_FRAMEWORK_VERSION
+---------------------------------
+
+.. versionadded:: 3.22
+
+Visual Studio target framework version.
+
+In some cases, the :ref:`Visual Studio Generators` may use an explicit value
+for the MSBuild ``TargetFrameworkVersion`` setting in ``.csproj`` files.
+CMake provides the chosen value in this variable.
+
+See the :variable:`CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION` variable
+and :prop_tgt:`DOTNET_TARGET_FRAMEWORK_VERSION` target property to
+specify custom ``TargetFrameworkVersion`` values for project targets.
+
+See also :variable:`CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER` and
+:variable:`CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION`.
index 59479af..c642a9f 100644 (file)
@@ -17,7 +17,6 @@ Known toolset version numbers are::
   140       = VS 2015 (14.0)
   141       = VS 2017 (15.0)
   142       = VS 2019 (16.0)
-  143       = VS 2022 (17.0)
 
 Compiler versions newer than those known to CMake will be reported
 as the latest known toolset version.
index 6d1e174..656b75e 100644 (file)
@@ -8,7 +8,7 @@ set(ASM_DIALECT "_MASM")
 
 set(CMAKE_ASM${ASM_DIALECT}_SOURCE_FILE_EXTENSIONS asm)
 
-set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> /c /Fo <OBJECT> <SOURCE>")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -c -Fo <OBJECT> <SOURCE>")
 
 # The ASM_MASM compiler id for this compiler is "MSVC", so fill out the runtime library table.
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         "")
index dad2750..a72575b 100644 (file)
@@ -35,7 +35,7 @@ if(NOT CMAKE_ASM_NASM_OBJECT_FORMAT)
 endif()
 
 if(NOT CMAKE_ASM_NASM_COMPILE_OBJECT)
-  set(CMAKE_ASM_NASM_COMPILE_OBJECT "<CMAKE_ASM_NASM_COMPILER> <INCLUDES> <FLAGS> -f ${CMAKE_ASM_NASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>")
+  set(CMAKE_ASM_NASM_COMPILE_OBJECT "<CMAKE_ASM_NASM_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -f ${CMAKE_ASM_NASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>")
 endif()
 
 if(CMAKE_ASM_NASM_COMPILER_ID STREQUAL "NASM")
index 754f235..2b24ff2 100644 (file)
@@ -5,6 +5,7 @@ set(CMAKE_C_COMPILER_VERSION "@CMAKE_C_COMPILER_VERSION@")
 set(CMAKE_C_COMPILER_VERSION_INTERNAL "@CMAKE_C_COMPILER_VERSION_INTERNAL@")
 set(CMAKE_C_COMPILER_WRAPPER "@CMAKE_C_COMPILER_WRAPPER@")
 set(CMAKE_C_STANDARD_COMPUTED_DEFAULT "@CMAKE_C_STANDARD_COMPUTED_DEFAULT@")
+set(CMAKE_C_EXTENSIONS_COMPUTED_DEFAULT "@CMAKE_C_EXTENSIONS_COMPUTED_DEFAULT@")
 set(CMAKE_C_COMPILE_FEATURES "@CMAKE_C_COMPILE_FEATURES@")
 set(CMAKE_C90_COMPILE_FEATURES "@CMAKE_C90_COMPILE_FEATURES@")
 set(CMAKE_C99_COMPILE_FEATURES "@CMAKE_C99_COMPILE_FEATURES@")
@@ -30,18 +31,9 @@ set(CMAKE_COMPILER_IS_GNUCC @CMAKE_COMPILER_IS_GNUCC@)
 set(CMAKE_C_COMPILER_LOADED 1)
 set(CMAKE_C_COMPILER_WORKS @CMAKE_C_COMPILER_WORKS@)
 set(CMAKE_C_ABI_COMPILED @CMAKE_C_ABI_COMPILED@)
-set(CMAKE_COMPILER_IS_MINGW @CMAKE_COMPILER_IS_MINGW@)
-set(CMAKE_COMPILER_IS_CYGWIN @CMAKE_COMPILER_IS_CYGWIN@)
-if(CMAKE_COMPILER_IS_CYGWIN)
-  set(CYGWIN 1)
-  set(UNIX 1)
-endif()
 
 set(CMAKE_C_COMPILER_ENV_VAR "CC")
 
-if(CMAKE_COMPILER_IS_MINGW)
-  set(MINGW 1)
-endif()
 set(CMAKE_C_COMPILER_ID_RUN 1)
 set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m)
 set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
index 1f19c00..43ede3e 100644 (file)
@@ -41,23 +41,34 @@ char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
 
 #if !defined(__STDC__) && !defined(__clang__)
 # if defined(_MSC_VER) || defined(__ibmxl__) || defined(__IBMC__)
-#  define C_DIALECT "90"
+#  define C_VERSION "90"
 # else
-#  define C_DIALECT
+#  define C_VERSION
 # endif
 #elif __STDC_VERSION__ > 201710L
-# define C_DIALECT "23"
+# define C_VERSION "23"
 #elif __STDC_VERSION__ >= 201710L
-# define C_DIALECT "17"
+# define C_VERSION "17"
 #elif __STDC_VERSION__ >= 201000L
-# define C_DIALECT "11"
+# define C_VERSION "11"
 #elif __STDC_VERSION__ >= 199901L
-# define C_DIALECT "99"
+# define C_VERSION "99"
 #else
-# define C_DIALECT "90"
+# define C_VERSION "90"
 #endif
-const char* info_language_dialect_default =
-  "INFO" ":" "dialect_default[" C_DIALECT "]";
+const char* info_language_standard_default =
+  "INFO" ":" "standard_default[" C_VERSION "]";
+
+const char* info_language_extensions_default = "INFO" ":" "extensions_default["
+// !defined(_MSC_VER) to exclude Clang's MSVC compatibility mode.
+#if (defined(__clang__) || defined(__GNUC__) ||                               \
+     defined(__TI_COMPILER_VERSION__)) &&                                     \
+  !defined(__STRICT_ANSI__) && !defined(_MSC_VER)
+  "ON"
+#else
+  "OFF"
+#endif
+"]";
 
 /*--------------------------------------------------------------------------*/
 
@@ -89,7 +100,8 @@ int main(int argc, char* argv[])
 #if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
   require += info_cray[argc];
 #endif
-  require += info_language_dialect_default[argc];
+  require += info_language_standard_default[argc];
+  require += info_language_extensions_default[argc];
   (void)argv;
   return require;
 }
index 6be1865..665f309 100644 (file)
@@ -91,6 +91,14 @@ if(CMAKE_USER_MAKE_RULES_OVERRIDE_C)
   set(CMAKE_USER_MAKE_RULES_OVERRIDE_C "${_override}")
 endif()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_C_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_C_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
 
 # for most systems a module is the same as a shared library
 # so unless the variable CMAKE_MODULE_EXISTS is set just
@@ -196,5 +204,3 @@ if(NOT CMAKE_EXECUTABLE_RPATH_LINK_C_FLAG)
 endif()
 
 set(CMAKE_C_INFORMATION_LOADED 1)
-
-
index 56ae732..2f3e9a8 100644 (file)
@@ -6,6 +6,7 @@ set(CMAKE_CUDA_COMPILER_VERSION "@CMAKE_CUDA_COMPILER_VERSION@")
 set(CMAKE_CUDA_DEVICE_LINKER "@CMAKE_CUDA_DEVICE_LINKER@")
 set(CMAKE_CUDA_FATBINARY "@CMAKE_CUDA_FATBINARY@")
 set(CMAKE_CUDA_STANDARD_COMPUTED_DEFAULT "@CMAKE_CUDA_STANDARD_COMPUTED_DEFAULT@")
+set(CMAKE_CUDA_EXTENSIONS_COMPUTED_DEFAULT "@CMAKE_CUDA_EXTENSIONS_COMPUTED_DEFAULT@")
 set(CMAKE_CUDA_COMPILE_FEATURES "@CMAKE_CUDA_COMPILE_FEATURES@")
 set(CMAKE_CUDA03_COMPILE_FEATURES "@CMAKE_CUDA03_COMPILE_FEATURES@")
 set(CMAKE_CUDA11_COMPILE_FEATURES "@CMAKE_CUDA11_COMPILE_FEATURES@")
index 91039e5..bc685a7 100644 (file)
@@ -16,7 +16,7 @@ char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
 @CMAKE_CUDA_COMPILER_ID_PLATFORM_CONTENT@
 @CMAKE_CUDA_COMPILER_ID_ERROR_FOR_TEST@
 
-const char* info_language_dialect_default = "INFO" ":" "dialect_default["
+const char* info_language_standard_default = "INFO" ":" "standard_default["
 #if __cplusplus > 202002L
   "23"
 #elif __cplusplus > 201703L
@@ -32,6 +32,16 @@ const char* info_language_dialect_default = "INFO" ":" "dialect_default["
 #endif
 "]";
 
+const char* info_language_extensions_default = "INFO" ":" "extensions_default["
+// !defined(_MSC_VER) to exclude Clang's MSVC compatibility mode.
+#if (defined(__clang__) || defined(__GNUC__)) && !defined(__STRICT_ANSI__) && \
+  !defined(_MSC_VER)
+  "ON"
+#else
+  "OFF"
+#endif
+"]";
+
 /*--------------------------------------------------------------------------*/
 
 int main(int argc, char* argv[])
@@ -48,7 +58,8 @@ int main(int argc, char* argv[])
 #ifdef SIMULATE_VERSION_MAJOR
   require += info_simulate_version[argc];
 #endif
-  require += info_language_dialect_default[argc];
+  require += info_language_standard_default[argc];
+  require += info_language_extensions_default[argc];
   (void)argv;
   return require;
 }
index a2946f4..e9cfed6 100644 (file)
@@ -100,6 +100,15 @@ if(NOT CMAKE_MODULE_EXISTS)
   set(CMAKE_SHARED_MODULE_CREATE_CUDA_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS})
 endif()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_CUDA_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_CUDA_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 # add the flags to the cache based
 # on the initial values computed in the platform/*.cmake files
 # use _INIT variables so that this only happens the first time
index d0ce77a..534e960 100644 (file)
@@ -5,6 +5,7 @@ set(CMAKE_CXX_COMPILER_VERSION "@CMAKE_CXX_COMPILER_VERSION@")
 set(CMAKE_CXX_COMPILER_VERSION_INTERNAL "@CMAKE_CXX_COMPILER_VERSION_INTERNAL@")
 set(CMAKE_CXX_COMPILER_WRAPPER "@CMAKE_CXX_COMPILER_WRAPPER@")
 set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT "@CMAKE_CXX_STANDARD_COMPUTED_DEFAULT@")
+set(CMAKE_CXX_EXTENSIONS_COMPUTED_DEFAULT "@CMAKE_CXX_EXTENSIONS_COMPUTED_DEFAULT@")
 set(CMAKE_CXX_COMPILE_FEATURES "@CMAKE_CXX_COMPILE_FEATURES@")
 set(CMAKE_CXX98_COMPILE_FEATURES "@CMAKE_CXX98_COMPILE_FEATURES@")
 set(CMAKE_CXX11_COMPILE_FEATURES "@CMAKE_CXX11_COMPILE_FEATURES@")
@@ -31,18 +32,9 @@ set(CMAKE_COMPILER_IS_GNUCXX @CMAKE_COMPILER_IS_GNUCXX@)
 set(CMAKE_CXX_COMPILER_LOADED 1)
 set(CMAKE_CXX_COMPILER_WORKS @CMAKE_CXX_COMPILER_WORKS@)
 set(CMAKE_CXX_ABI_COMPILED @CMAKE_CXX_ABI_COMPILED@)
-set(CMAKE_COMPILER_IS_MINGW @CMAKE_COMPILER_IS_MINGW@)
-set(CMAKE_COMPILER_IS_CYGWIN @CMAKE_COMPILER_IS_CYGWIN@)
-if(CMAKE_COMPILER_IS_CYGWIN)
-  set(CYGWIN 1)
-  set(UNIX 1)
-endif()
 
 set(CMAKE_CXX_COMPILER_ENV_VAR "CXX")
 
-if(CMAKE_COMPILER_IS_MINGW)
-  set(MINGW 1)
-endif()
 set(CMAKE_CXX_COMPILER_ID_RUN 1)
 set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP;ixx;cppm)
 set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC)
index 7362a08..cdf9c18 100644 (file)
@@ -49,7 +49,7 @@ char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
 #  define CXX_STD __cplusplus
 #endif
 
-const char* info_language_dialect_default = "INFO" ":" "dialect_default["
+const char* info_language_standard_default = "INFO" ":" "standard_default["
 #if CXX_STD > 202002L
   "23"
 #elif CXX_STD > 201703L
@@ -65,6 +65,17 @@ const char* info_language_dialect_default = "INFO" ":" "dialect_default["
 #endif
 "]";
 
+const char* info_language_extensions_default = "INFO" ":" "extensions_default["
+// !defined(_MSC_VER) to exclude Clang's MSVC compatibility mode.
+#if (defined(__clang__) || defined(__GNUC__) ||                               \
+     defined(__TI_COMPILER_VERSION__)) &&                                     \
+  !defined(__STRICT_ANSI__) && !defined(_MSC_VER)
+  "ON"
+#else
+  "OFF"
+#endif
+"]";
+
 /*--------------------------------------------------------------------------*/
 
 int main(int argc, char* argv[])
@@ -87,7 +98,8 @@ int main(int argc, char* argv[])
 #if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
   require += info_cray[argc];
 #endif
-  require += info_language_dialect_default[argc];
+  require += info_language_standard_default[argc];
+  require += info_language_extensions_default[argc];
   (void)argv;
   return require;
 }
index 944d236..53abf37 100644 (file)
@@ -193,6 +193,15 @@ foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
   endif()
 endforeach()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_CXX_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_CXX_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 # add the flags to the cache based
 # on the initial values computed in the platform/*.cmake files
 # use _INIT variables so that this only happens the first time
index 05174de..bda1d71 100644 (file)
@@ -32,5 +32,6 @@ macro (CHECK_COMPILER_FLAG_COMMON_PATTERNS _VAR)
     FAIL_REGEX "Warning: illegal option"                   # SunStudio 12
     FAIL_REGEX "[Ww]arning: Invalid suboption"             # Fujitsu
     FAIL_REGEX "An invalid option .* appears on the command line" # Cray
+    FAIL_REGEX "WARNING: invalid compiler option"          # TI armcl
   )
 endmacro ()
index 96855d2..b7c478f 100644 (file)
@@ -10,44 +10,62 @@ Macro to provide an option dependent on other options.
 This macro presents an option to the user only if a set of other
 conditions are true.
 
-Usage:
+.. command:: cmake_dependent_option
 
-.. code-block:: cmake
+  .. code-block:: cmake
 
-  cmake_dependent_option(<option> "<help_text>" <value> <depends> <force>)
+    cmake_dependent_option(<option> "<help_text>" <value> <depends> <force>)
 
-Where ``<option>`` is available to the user if ``<depends>`` is true. When
-``<option>`` is available, the given ``<help_text>`` and initial ``<value>``
-are used. If the ``<depends>`` condition is not true, ``<option>`` will not be
-presented and will always have the value given by ``<force>``. Any value set by
-the user is preserved for when the option is presented again. Each element in
-the fourth parameter is evaluated as an if-condition, so
-:ref:`Condition Syntax` can be used.
+  Makes ``<option>`` available to the user if ``<depends>`` is true. When
+  ``<option>`` is available, the given ``<help_text>`` and initial ``<value>``
+  are used. If the ``<depends>`` condition is not true, ``<option>`` will not be
+  presented and will always have the value given by ``<force>``. Any value set by
+  the user is preserved for when the option is presented again. In case ``<depends>``
+  is a :ref:`semicolon-separated list <CMake Language Lists>`, all elements must
+  be true in order to initialize ``<option>`` with ``<value>``.
 
 Example invocation:
 
 .. code-block:: cmake
 
-  cmake_dependent_option(USE_FOO "Use Foo" ON
-                         "USE_BAR;NOT USE_ZOT" OFF)
+  cmake_dependent_option(USE_FOO "Use Foo" ON "USE_BAR;NOT USE_ZOT" OFF)
 
 If ``USE_BAR`` is true and ``USE_ZOT`` is false, this provides an option called
 ``USE_FOO`` that defaults to ON. Otherwise, it sets ``USE_FOO`` to OFF and
 hides the option from the user. If the status of ``USE_BAR`` or ``USE_ZOT``
 ever changes, any value for the ``USE_FOO`` option is saved so that when the
 option is re-enabled it retains its old value.
+
+.. versionadded:: 3.22
+
+  Full :ref:`Condition Syntax` is now supported.  See policy :policy:`CMP0127`.
+
 #]=======================================================================]
 
 macro(CMAKE_DEPENDENT_OPTION option doc default depends force)
+  cmake_policy(GET CMP0127 _CDO_CMP0127
+    PARENT_SCOPE # undocumented, do not use outside of CMake
+    )
   if(${option}_ISSET MATCHES "^${option}_ISSET$")
     set(${option}_AVAILABLE 1)
-    foreach(d ${depends})
-      string(REGEX REPLACE " +" ";" CMAKE_DEPENDENT_OPTION_DEP "${d}")
-      if(${CMAKE_DEPENDENT_OPTION_DEP})
-      else()
-        set(${option}_AVAILABLE 0)
-      endif()
-    endforeach()
+    if("x${_CDO_CMP0127}x" STREQUAL "xNEWx")
+      foreach(d ${depends})
+        cmake_language(EVAL CODE "
+          if (${d})
+          else()
+            set(${option}_AVAILABLE 0)
+          endif()"
+        )
+      endforeach()
+    else()
+      foreach(d ${depends})
+        string(REGEX REPLACE " +" ";" CMAKE_DEPENDENT_OPTION_DEP "${d}")
+        if(${CMAKE_DEPENDENT_OPTION_DEP})
+        else()
+          set(${option}_AVAILABLE 0)
+        endif()
+      endforeach()
+    endif()
     if(${option}_AVAILABLE)
       option(${option} "${doc}" "${default}")
       set(${option} "${${option}}" CACHE BOOL "${doc}" FORCE)
@@ -61,4 +79,9 @@ macro(CMAKE_DEPENDENT_OPTION option doc default depends force)
   else()
     set(${option} "${${option}_ISSET}")
   endif()
+  if("x${_CDO_CMP0127}x" STREQUAL "xx" AND "x${depends}x" MATCHES "[^A-Za-z0-9_; ]")
+    cmake_policy(GET_WARNING CMP0127 _CDO_CMP0127_WARNING)
+    message(AUTHOR_WARNING "${_CDO_CMP0127_WARNING}")
+  endif()
+  unset(_CDO_CMP0127)
 endmacro()
index e8b9db7..a1814b7 100644 (file)
@@ -125,6 +125,7 @@ if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
   include(CMakeDetermineCompilerId)
   set(userflags)
   CMAKE_DETERMINE_COMPILER_ID_VENDOR(ASM${ASM_DIALECT} "${userflags}")
+  set(_variant "")
   if("x${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}" STREQUAL "xIAR")
     # primary necessary to detect architecture, so the right archiver and linker can be picked
     # eg. "IAR Assembler V8.10.1.12857/W32 for ARM" or "IAR Assembler V4.11.1.4666 for Renesas RX"
@@ -137,6 +138,19 @@ if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
     if(_all_compileid_matches)
       list(GET _all_compileid_matches "-1" CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID)
     endif()
+  elseif("x${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}" STREQUAL "xClang")
+    # Test whether an MSVC-like command-line option works.
+    execute_process(COMMAND ${CMAKE_ASM${ASM_DIALECT}_COMPILER} -?
+      OUTPUT_VARIABLE _clang_output
+      ERROR_VARIABLE _clang_output
+      RESULT_VARIABLE _clang_result)
+      if(_clang_result EQUAL 0)
+        set(CMAKE_ASM${ASM_DIALECT}_COMPILER_FRONTEND_VARIANT "MSVC")
+        set(CMAKE_ASM${ASM_DIALECT}_SIMULATE_ID MSVC)
+      else()
+        set(CMAKE_ASM${ASM_DIALECT}_COMPILER_FRONTEND_VARIANT "GNU")
+      endif()
+      set(_variant " with ${CMAKE_ASM${ASM_DIALECT}_COMPILER_FRONTEND_VARIANT}-like command-line")
   endif()
 
   _cmake_find_compiler_sysroot(ASM${ASM_DIALECT})
@@ -144,6 +158,8 @@ if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
   unset(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_OUTPUT)
   unset(_all_compileid_matches)
   unset(_compileid)
+  unset(_clang_result)
+  unset(_clang_output)
 endif()
 
 if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
@@ -157,9 +173,10 @@ if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
   else()
     set(_archid "")
   endif()
-  message(STATUS "The ASM${ASM_DIALECT} compiler identification is ${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}${_archid}${_version}")
+  message(STATUS "The ASM${ASM_DIALECT} compiler identification is ${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}${_archid}${_version}${_variant}")
   unset(_archid)
   unset(_version)
+  unset(_variant)
 else()
   message(STATUS "The ASM${ASM_DIALECT} compiler identification is unknown")
 endif()
index 0f80f9c..15eab0f 100644 (file)
@@ -128,11 +128,6 @@ if(NOT CMAKE_C_COMPILER_ID_RUN)
   if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
     set(CMAKE_COMPILER_IS_GNUCC 1)
   endif()
-  if(CMAKE_C_PLATFORM_ID MATCHES "MinGW")
-    set(CMAKE_COMPILER_IS_MINGW 1)
-  elseif(CMAKE_C_PLATFORM_ID MATCHES "Cygwin")
-    set(CMAKE_COMPILER_IS_CYGWIN 1)
-  endif()
 else()
   if(NOT DEFINED CMAKE_C_COMPILER_FRONTEND_VARIANT)
     # Some toolchain files set our internal CMAKE_C_COMPILER_ID_RUN
index e360d31..d06315e 100644 (file)
@@ -192,17 +192,31 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN)
       get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY)
       get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY)
     endif()
+
+    if(_CUDA_NVCC_OUT MATCHES "\\#\\$ NVVMIR_LIBRARY_DIR=([^\r\n]*)")
+      get_filename_component(_CUDA_NVVMIR_LIBRARY_DIR "${CMAKE_MATCH_1}" ABSOLUTE)
+
+      #We require the path to end in `/nvvm/libdevice'
+      if(_CUDA_NVVMIR_LIBRARY_DIR MATCHES "nvvm/libdevice$")
+        get_filename_component(_CUDA_NVVMIR_LIBRARY_DIR "${_CUDA_NVVMIR_LIBRARY_DIR}/../.." ABSOLUTE)
+        set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT_FROM_NVVMIR_LIBRARY_DIR "${_CUDA_NVVMIR_LIBRARY_DIR}")
+      endif()
+
+      unset(_CUDA_NVVMIR_LIBRARY_DIR)
+      unset(_cuda_nvvmir_dir_name)
+    endif()
     unset(_CUDA_NVCC_OUT)
 
     set(CMAKE_CUDA_DEVICE_LINKER "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/bin/nvlink${CMAKE_EXECUTABLE_SUFFIX}")
     set(CMAKE_CUDA_FATBINARY "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/bin/fatbinary${CMAKE_EXECUTABLE_SUFFIX}")
 
-
     # In a non-scattered installation the following are equivalent to CMAKE_CUDA_COMPILER_TOOLKIT_ROOT.
     # We first check for a non-scattered installation to prefer it over a scattered installation.
 
     # CMAKE_CUDA_COMPILER_LIBRARY_ROOT contains the device library.
-    if(EXISTS "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/nvvm/libdevice")
+    if(DEFINED CMAKE_CUDA_COMPILER_LIBRARY_ROOT_FROM_NVVMIR_LIBRARY_DIR)
+      set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_LIBRARY_ROOT_FROM_NVVMIR_LIBRARY_DIR}")
+    elseif(EXISTS "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/nvvm/libdevice")
       set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}")
     elseif(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/nvvm/libdevice")
       set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_SYSROOT_LINK}/usr/lib/cuda")
@@ -211,6 +225,7 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN)
     else()
       message(FATAL_ERROR "Couldn't find CUDA library root.")
     endif()
+    unset(CMAKE_CUDA_COMPILER_LIBRARY_ROOT_FROM_NVVMIR_LIBRARY_DIR)
 
     # CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT contains the linking stubs necessary for device linking and other low-level library files.
     if(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/nvidia-cuda-toolkit/bin/crt/link.stub")
@@ -426,9 +441,10 @@ elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
       if("${_nvcc_output_line}" MATCHES "^ *nvlink")
         string(APPEND _nvcc_log "    ignoring nvlink line\n")
       elseif(_nvcc_libraries)
-        if("${_nvcc_output_line}" MATCHES "(@\"?tmp/a\\.exe\\.res\"?)")
+        if("${_nvcc_output_line}" MATCHES "(@\"?((tmp/)?a\\.exe\\.res)\"?)")
           set(_nvcc_link_res_arg "${CMAKE_MATCH_1}")
-          set(_nvcc_link_res "${CMAKE_PLATFORM_INFO_DIR}/CompilerIdCUDA/tmp/a.exe.res")
+          set(_nvcc_link_res_file "${CMAKE_MATCH_2}")
+          set(_nvcc_link_res "${CMAKE_PLATFORM_INFO_DIR}/CompilerIdCUDA/${_nvcc_link_res_file}")
           if(EXISTS "${_nvcc_link_res}")
             file(READ "${_nvcc_link_res}" _nvcc_link_res_content)
             string(REPLACE "${_nvcc_link_res_arg}" "${_nvcc_link_res_content}" _nvcc_output_line "${_nvcc_output_line}")
index 556518f..72dc8d3 100644 (file)
@@ -125,11 +125,6 @@ if(NOT CMAKE_CXX_COMPILER_ID_RUN)
   if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
     set(CMAKE_COMPILER_IS_GNUCXX 1)
   endif()
-  if(CMAKE_CXX_PLATFORM_ID MATCHES "MinGW")
-    set(CMAKE_COMPILER_IS_MINGW 1)
-  elseif(CMAKE_CXX_PLATFORM_ID MATCHES "Cygwin")
-    set(CMAKE_COMPILER_IS_CYGWIN 1)
-  endif()
 else()
   if(NOT DEFINED CMAKE_CXX_COMPILER_FRONTEND_VARIANT)
     # Some toolchain files set our internal CMAKE_CXX_COMPILER_ID_RUN
index e564517..c62cb7d 100644 (file)
@@ -267,6 +267,7 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
   set(CMAKE_${lang}_SIMULATE_ID "${CMAKE_${lang}_SIMULATE_ID}" PARENT_SCOPE)
   set(CMAKE_${lang}_SIMULATE_VERSION "${CMAKE_${lang}_SIMULATE_VERSION}" PARENT_SCOPE)
   set(CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT "${CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT}" PARENT_SCOPE)
+  set(CMAKE_${lang}_EXTENSIONS_COMPUTED_DEFAULT "${CMAKE_${lang}_EXTENSIONS_COMPUTED_DEFAULT}" PARENT_SCOPE)
   set(CMAKE_${lang}_COMPILER_PRODUCED_OUTPUT "${COMPILER_${lang}_PRODUCED_OUTPUT}" PARENT_SCOPE)
   set(CMAKE_${lang}_COMPILER_PRODUCED_FILES "${COMPILER_${lang}_PRODUCED_FILES}" PARENT_SCOPE)
 endfunction()
@@ -319,13 +320,15 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
       set(id_cl "$(CLToolExe)")
     elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
       set(id_cl clang.exe)
+    # Executable names have been chosen according documentation
+    # URL: (https://software.intel.com/content/www/us/en/develop/documentation/get-started-with-dpcpp-compiler/top.html#top_GUID-A9B4C91D-97AC-450D-9742-9D895BC8AEE1)
     elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "Intel")
       if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "DPC\\+\\+ Compiler")
         set(id_cl dpcpp.exe)
-      elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "C\\+\\+ Compiler ([8-9]\\.|1[0-9]\\.|XE)")
-        set(id_cl icl.exe)
-      elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "C\\+\\+ Compiler")
+      elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "C\\+\\+ Compiler 2021")
         set(id_cl icx.exe)
+      elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "C\\+\\+ Compiler")
+        set(id_cl icl.exe)
       endif()
     else()
       set(id_cl cl.exe)
@@ -418,6 +421,15 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
     if(CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR)
       set(id_ToolsetVCTargetsDir "<VCTargetsPath>${CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR}</VCTargetsPath>")
     endif()
+    if(CMAKE_VS_TARGET_FRAMEWORK_VERSION)
+      set(id_TargetFrameworkVersion "<TargetFrameworkVersion>${CMAKE_VS_TARGET_FRAMEWORK_VERSION}</TargetFrameworkVersion>")
+    endif()
+    if(CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER)
+      set(id_TargetFrameworkIdentifier "<TargetFrameworkIdentifier>${CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER}</TargetFrameworkIdentifier>")
+    endif()
+    if(CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION)
+      set(id_TargetFrameworkTargetsVersion "<TargetFrameworkTargetsVersion>${CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION}</TargetFrameworkTargetsVersion>")
+    endif()
     set(id_CustomGlobals "")
     foreach(pair IN LISTS CMAKE_VS_GLOBALS)
       if("${pair}" MATCHES "([^=]+)=(.*)$")
@@ -536,7 +548,8 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
     else()
       set(id_toolset "")
     endif()
-    if("${lang}" STREQUAL "Swift")
+    set(id_lang_version "")
+    if("x${lang}" STREQUAL "xSwift")
       if(CMAKE_Swift_LANGUAGE_VERSION)
         set(id_lang_version "SWIFT_VERSION = ${CMAKE_Swift_LANGUAGE_VERSION};")
       elseif(XCODE_VERSION VERSION_GREATER_EQUAL 10.2)
@@ -546,8 +559,14 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
       else()
         set(id_lang_version "SWIFT_VERSION = 2.3;")
       endif()
-    else()
-      set(id_lang_version "")
+    elseif("x${lang}" STREQUAL "xC" OR "x${lang}" STREQUAL "xOBJC")
+      if(CMAKE_${lang}_COMPILER_ID_FLAGS MATCHES "(^| )(-std=[^ ]+)( |$)")
+        set(id_lang_version "OTHER_CFLAGS = \"${CMAKE_MATCH_2}\";")
+      endif()
+    elseif("x${lang}" STREQUAL "xCXX" OR "x${lang}" STREQUAL "xOBJCXX")
+      if(CMAKE_${lang}_COMPILER_ID_FLAGS MATCHES "(^| )(-std=[^ ]+)( |$)")
+        set(id_lang_version "OTHER_CPLUSPLUSFLAGS = \"${CMAKE_MATCH_2}\";")
+      endif()
     endif()
     if(CMAKE_OSX_DEPLOYMENT_TARGET)
       set(id_deployment_target
@@ -685,7 +704,7 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
   # Check the result of compilation.
   if(CMAKE_${lang}_COMPILER_ID_RESULT
      # Intel Fortran warns and ignores preprocessor lines without /fpp
-     OR CMAKE_${lang}_COMPILER_ID_OUTPUT MATCHES "Bad # preprocessor line"
+     OR CMAKE_${lang}_COMPILER_ID_OUTPUT MATCHES "warning #5117: Bad # preprocessor line"
      )
     # Compilation failed.
     set(MSG
@@ -696,7 +715,10 @@ ${CMAKE_${lang}_COMPILER_ID_RESULT}
 ${CMAKE_${lang}_COMPILER_ID_OUTPUT}
 
 ")
-    file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "${MSG}")
+    # Log the output unless we recognize it as a known-bad case.
+    if(NOT CMAKE_${lang}_COMPILER_ID_OUTPUT MATCHES "warning #5117: Bad # preprocessor line")
+      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "${MSG}")
+    endif()
 
     # Some languages may know the correct/desired set of flags and want to fail right away if they don't work.
     # This is currently only used by CUDA.
@@ -876,9 +898,12 @@ function(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file)
       if("${info}" MATCHES "INFO:qnxnto\\[\\]")
         set(COMPILER_QNXNTO 1)
       endif()
-      if("${info}" MATCHES "INFO:dialect_default\\[([^]\"]*)\\]")
+      if("${info}" MATCHES "INFO:standard_default\\[([^]\"]*)\\]")
         set(CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT "${CMAKE_MATCH_1}")
       endif()
+      if("${info}" MATCHES "INFO:extensions_default\\[([^]\"]*)\\]")
+        set(CMAKE_${lang}_EXTENSIONS_COMPUTED_DEFAULT "${CMAKE_MATCH_1}")
+      endif()
     endforeach()
 
     # Construct compiler version from components if needed.
@@ -988,6 +1013,7 @@ function(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file)
   set(CMAKE_${lang}_SIMULATE_VERSION "${CMAKE_${lang}_SIMULATE_VERSION}" PARENT_SCOPE)
   set(COMPILER_QNXNTO "${COMPILER_QNXNTO}" PARENT_SCOPE)
   set(CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT "${CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT}" PARENT_SCOPE)
+  set(CMAKE_${lang}_EXTENSIONS_COMPUTED_DEFAULT "${CMAKE_${lang}_EXTENSIONS_COMPUTED_DEFAULT}" PARENT_SCOPE)
 endfunction()
 
 #-----------------------------------------------------------------------------
index d7d032c..6a8984b 100644 (file)
@@ -235,11 +235,6 @@ if(NOT CMAKE_Fortran_COMPILER_ID_RUN)
   if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
     set(CMAKE_COMPILER_IS_GNUG77 1)
   endif()
-  if(CMAKE_Fortran_PLATFORM_ID MATCHES "MinGW")
-    set(CMAKE_COMPILER_IS_MINGW 1)
-  elseif(CMAKE_Fortran_PLATFORM_ID MATCHES "Cygwin")
-    set(CMAKE_COMPILER_IS_CYGWIN 1)
-  endif()
 endif()
 
 if (NOT _CMAKE_TOOLCHAIN_LOCATION)
index 84fde49..6c81754 100644 (file)
@@ -82,8 +82,7 @@ if(("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" AND
   if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xClang")
     set(_CMAKE_NM_NAMES "llvm-nm" "nm")
     list(PREPEND _CMAKE_AR_NAMES "llvm-lib")
-    # llvm-mt does not support all flags we need in vs_link_exe
-    # list(PREPEND _CMAKE_MT_NAMES "llvm-mt")
+    list(PREPEND _CMAKE_MT_NAMES "llvm-mt")
     list(PREPEND _CMAKE_LINKER_NAMES "lld-link")
     list(APPEND _CMAKE_TOOL_VARS NM)
   elseif("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xIntel")
@@ -118,7 +117,7 @@ elseif("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" MATCHES "^xIAR$")
   endfunction()
 
   __resolve_IAR_hints("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER}" _CMAKE_TOOLCHAIN_LOCATION)
-  set(_CMAKE_IAR_ITOOLS "ARM" "RX" "RH850" "RL78" "RISCV" "STM8")
+  set(_CMAKE_IAR_ITOOLS "ARM" "RX" "RH850" "RL78" "RISCV" "RISC-V" "STM8")
   set(_CMAKE_IAR_XTOOLS "AVR" "MSP430" "V850" "8051")
 
   if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" IN_LIST _CMAKE_IAR_ITOOLS)
@@ -173,15 +172,7 @@ else()
     else()
       list(PREPEND _CMAKE_LINKER_NAMES "ld.lld")
     endif()
-    if(APPLE)
-      # llvm-ar does not generate a symbol table that the Apple ld64 linker accepts.
-      # FIXME(#23333): We still need to consider 'llvm-ar' as a fallback because
-      # the 'APPLE' definition may be based on the host in this context, and a
-      # cross-compiling toolchain may not have 'ar'.
-      list(APPEND _CMAKE_AR_NAMES "llvm-ar")
-    else()
-      list(PREPEND _CMAKE_AR_NAMES "llvm-ar")
-    endif()
+    list(PREPEND _CMAKE_AR_NAMES "llvm-ar")
     list(PREPEND _CMAKE_RANLIB_NAMES "llvm-ranlib")
     if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION}" VERSION_GREATER_EQUAL 11)
       # llvm-strip versions prior to 11 require additional flags we do not yet add.
index 815dfc9..726e2a2 100644 (file)
@@ -78,7 +78,7 @@ if(UNIX)
   # from the outside
   if(NOT CMAKE_SIZEOF_VOID_P)
     set(CMAKE_SIZEOF_VOID_P 4)
-    if(EXISTS /usr/lib64)
+    if(EXISTS ${CMAKE_SYSROOT}/usr/lib64)
       set(CMAKE_SIZEOF_VOID_P 8)
     else()
       # use the file utility to check whether itself is 64 bit:
index d474f96..97f891e 100644 (file)
@@ -19,20 +19,11 @@ set(CMAKE_COMPILER_IS_GNUG77 @CMAKE_COMPILER_IS_GNUG77@)
 set(CMAKE_Fortran_COMPILER_LOADED 1)
 set(CMAKE_Fortran_COMPILER_WORKS @CMAKE_Fortran_COMPILER_WORKS@)
 set(CMAKE_Fortran_ABI_COMPILED @CMAKE_Fortran_ABI_COMPILED@)
-set(CMAKE_COMPILER_IS_MINGW @CMAKE_COMPILER_IS_MINGW@)
-set(CMAKE_COMPILER_IS_CYGWIN @CMAKE_COMPILER_IS_CYGWIN@)
-if(CMAKE_COMPILER_IS_CYGWIN)
-  set(CYGWIN 1)
-  set(UNIX 1)
-endif()
 
 set(CMAKE_Fortran_COMPILER_ENV_VAR "FC")
 
 set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 @CMAKE_Fortran_COMPILER_SUPPORTS_F90@)
 
-if(CMAKE_COMPILER_IS_MINGW)
-  set(MINGW 1)
-endif()
 set(CMAKE_Fortran_COMPILER_ID_RUN 1)
 set(CMAKE_Fortran_SOURCE_FILE_EXTENSIONS f;F;fpp;FPP;f77;F77;f90;F90;for;For;FOR;f95;F95)
 set(CMAKE_Fortran_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
diff --git a/Modules/CMakeFortranCompilerABI.F90 b/Modules/CMakeFortranCompilerABI.F90
new file mode 100644 (file)
index 0000000..4a17153
--- /dev/null
@@ -0,0 +1,48 @@
+program CMakeFortranCompilerABI
+
+implicit none
+
+integer :: i(1) = 0
+where (i==0) i=1
+if (any(i/=1)) stop 1
+! showing Fortran 90 syntax is OK
+
+#if 0
+! Address Size
+#endif
+#if defined(_LP64)
+PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(_M_IA64)
+PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(_M_X64)
+PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(_M_AMD64)
+PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(__x86_64__)
+PRINT *, 'INFO:sizeof_dptr[8]'
+
+#elif defined(_ILP32)
+PRINT *, 'INFO:sizeof_dptr[4]'
+#elif defined(_M_IX86)
+PRINT *, 'INFO:sizeof_dptr[4]'
+#elif defined(__i386__)
+PRINT *, 'INFO:sizeof_dptr[4]'
+
+#elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8
+PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 4
+PRINT *, 'INFO:sizeof_dptr[4]'
+#elif defined(__SIZEOF_SIZE_T__) && __SIZEOF_SIZE_T__ == 8
+PRINT *, 'INFO:sizeof_dptr[8]'
+#elif defined(__SIZEOF_SIZE_T__) && __SIZEOF_SIZE_T__ == 4
+PRINT *, 'INFO:sizeof_dptr[4]'
+#endif
+
+#if 0
+! Application Binary Interface
+#endif
+#if defined(__ELF__)
+PRINT *, 'INFO:abi[ELF]'
+#endif
+PRINT *, 'ABI Detection'
+end program
index 9a4ce63..0f71c6f 100644 (file)
@@ -157,6 +157,15 @@ if(NOT CMAKE_INCLUDE_FLAG_Fortran)
   set(CMAKE_INCLUDE_FLAG_Fortran ${CMAKE_INCLUDE_FLAG_C})
 endif()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_Fortran_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_Fortran_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 set(CMAKE_VERBOSE_MAKEFILE FALSE CACHE BOOL "If this value is on, makefiles will be generated without the .SILENT directive, and all commands will be echoed to the console during the make.  This is useful for debugging only. With Visual Studio IDE projects all commands are done without /nologo.")
 
 set(CMAKE_Fortran_FLAGS_INIT "$ENV{FFLAGS} ${CMAKE_Fortran_FLAGS_INIT}")
index 17633a8..ce4e2cf 100644 (file)
@@ -2,6 +2,7 @@ set(CMAKE_HIP_COMPILER "@CMAKE_HIP_COMPILER@")
 set(CMAKE_HIP_COMPILER_ID "@CMAKE_HIP_COMPILER_ID@")
 set(CMAKE_HIP_COMPILER_VERSION "@CMAKE_HIP_COMPILER_VERSION@")
 set(CMAKE_HIP_STANDARD_COMPUTED_DEFAULT "@CMAKE_HIP_STANDARD_COMPUTED_DEFAULT@")
+set(CMAKE_HIP_EXTENSIONS_COMPUTED_DEFAULT "@CMAKE_HIP_EXTENSIONS_COMPUTED_DEFAULT@")
 set(CMAKE_HIP_COMPILE_FEATURES "@CMAKE_HIP_COMPILE_FEATURES@")
 set(CMAKE_HIP98_COMPILE_FEATURES "@CMAKE_HIP03_COMPILE_FEATURES@")
 set(CMAKE_HIP11_COMPILE_FEATURES "@CMAKE_HIP11_COMPILE_FEATURES@")
index 5258efb..3c4a1d4 100644 (file)
@@ -16,7 +16,7 @@ char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
 @CMAKE_HIP_COMPILER_ID_PLATFORM_CONTENT@
 @CMAKE_HIP_COMPILER_ID_ERROR_FOR_TEST@
 
-const char* info_language_dialect_default = "INFO" ":" "dialect_default["
+const char* info_language_standard_default = "INFO" ":" "standard_default["
 #if __cplusplus > 202002L
   "23"
 #elif __cplusplus > 201703L
@@ -32,6 +32,14 @@ const char* info_language_dialect_default = "INFO" ":" "dialect_default["
 #endif
 "]";
 
+const char* info_language_extensions_default = "INFO" ":" "extensions_default["
+#if (defined(__clang__) || defined(__GNUC__)) && !defined(__STRICT_ANSI__)
+  "ON"
+#else
+  "OFF"
+#endif
+"]";
+
 /*--------------------------------------------------------------------------*/
 
 int main(int argc, char* argv[])
@@ -48,7 +56,8 @@ int main(int argc, char* argv[])
 #ifdef SIMULATE_VERSION_MAJOR
   require += info_simulate_version[argc];
 #endif
-  require += info_language_dialect_default[argc];
+  require += info_language_standard_default[argc];
+  require += info_language_extensions_default[argc];
   (void)argv;
   return require;
 }
index 28c5f18..4c57677 100644 (file)
@@ -68,6 +68,15 @@ if(NOT CMAKE_MODULE_EXISTS)
   set(CMAKE_SHARED_MODULE_CREATE_HIP_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_HIP_FLAGS})
 endif()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_HIP_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_HIP_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 # add the flags to the cache based
 # on the initial values computed in the platform/*.cmake files
 # use _INIT variables so that this only happens the first time
index ab67bf3..36f6ec1 100644 (file)
@@ -5,6 +5,7 @@ set(CMAKE_OBJC_COMPILER_VERSION "@CMAKE_OBJC_COMPILER_VERSION@")
 set(CMAKE_OBJC_COMPILER_VERSION_INTERNAL "@CMAKE_OBJC_COMPILER_VERSION_INTERNAL@")
 set(CMAKE_OBJC_COMPILER_WRAPPER "@CMAKE_OBJC_COMPILER_WRAPPER@")
 set(CMAKE_OBJC_STANDARD_COMPUTED_DEFAULT "@CMAKE_OBJC_STANDARD_COMPUTED_DEFAULT@")
+set(CMAKE_OBJC_EXTENSIONS_COMPUTED_DEFAULT "@CMAKE_OBJC_EXTENSIONS_COMPUTED_DEFAULT@")
 set(CMAKE_OBJC_COMPILE_FEATURES "@CMAKE_OBJC_COMPILE_FEATURES@")
 set(CMAKE_OBJC90_COMPILE_FEATURES "@CMAKE_OBJC90_COMPILE_FEATURES@")
 set(CMAKE_OBJC99_COMPILE_FEATURES "@CMAKE_OBJC99_COMPILE_FEATURES@")
index 418fd48..89bfe02 100644 (file)
@@ -23,23 +23,31 @@ char const* qnxnto = "INFO" ":" "qnxnto[]";
 #if !defined(__STDC__)
 # if (defined(_MSC_VER) && !defined(__clang__)) \
   || (defined(__ibmxl__) || defined(__IBMC__))
-#  define C_DIALECT "90"
+#  define C_VERSION "90"
 # else
-#  define C_DIALECT
+#  define C_VERSION
 # endif
 #elif __STDC_VERSION__ > 201710L
-# define C_DIALECT "23"
+# define C_VERSION "23"
 #elif __STDC_VERSION__ >= 201710L
-# define C_DIALECT "17"
+# define C_VERSION "17"
 #elif __STDC_VERSION__ >= 201000L
-# define C_DIALECT "11"
+# define C_VERSION "11"
 #elif __STDC_VERSION__ >= 199901L
-# define C_DIALECT "99"
+# define C_VERSION "99"
 #else
-# define C_DIALECT "90"
+# define C_VERSION "90"
 #endif
-const char* info_language_dialect_default =
-  "INFO" ":" "dialect_default[" C_DIALECT "]";
+const char* info_language_standard_default =
+  "INFO" ":" "standard_default[" C_VERSION "]";
+
+const char* info_language_extensions_default = "INFO" ":" "extensions_default["
+#if (defined(__clang__) || defined(__GNUC__)) && !defined(__STRICT_ANSI__)
+  "ON"
+#else
+  "OFF"
+#endif
+"]";
 
 /*--------------------------------------------------------------------------*/
 
@@ -61,7 +69,8 @@ int main(int argc, char* argv[])
 #ifdef SIMULATE_VERSION_MAJOR
   require += info_simulate_version[argc];
 #endif
-  require += info_language_dialect_default[argc];
+  require += info_language_standard_default[argc];
+  require += info_language_extensions_default[argc];
   (void)argv;
   return require;
 }
index ac67d01..4c697da 100644 (file)
@@ -91,6 +91,15 @@ if(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJC)
   set(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJC "${_override}")
 endif()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_OBJC_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_OBJC_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 
 # for most systems a module is the same as a shared library
 # so unless the variable CMAKE_MODULE_EXISTS is set just
index a24582b..4f27100 100644 (file)
@@ -5,6 +5,7 @@ set(CMAKE_OBJCXX_COMPILER_VERSION "@CMAKE_OBJCXX_COMPILER_VERSION@")
 set(CMAKE_OBJCXX_COMPILER_VERSION_INTERNAL "@CMAKE_OBJCXX_COMPILER_VERSION_INTERNAL@")
 set(CMAKE_OBJCXX_COMPILER_WRAPPER "@CMAKE_OBJCXX_COMPILER_WRAPPER@")
 set(CMAKE_OBJCXX_STANDARD_COMPUTED_DEFAULT "@CMAKE_OBJCXX_STANDARD_COMPUTED_DEFAULT@")
+set(CMAKE_OBJCXX_EXTENSIONS_COMPUTED_DEFAULT "@CMAKE_OBJCXX_EXTENSIONS_COMPUTED_DEFAULT@")
 set(CMAKE_OBJCXX_COMPILE_FEATURES "@CMAKE_OBJCXX_COMPILE_FEATURES@")
 set(CMAKE_OBJCXX98_COMPILE_FEATURES "@CMAKE_OBJCXX98_COMPILE_FEATURES@")
 set(CMAKE_OBJCXX11_COMPILE_FEATURES "@CMAKE_OBJCXX11_COMPILE_FEATURES@")
index e2ac35d..2145b40 100644 (file)
@@ -29,7 +29,7 @@ char const* qnxnto = "INFO" ":" "qnxnto[]";
 #define CXX_STD __cplusplus
 #endif
 
-const char* info_language_dialect_default = "INFO" ":" "dialect_default["
+const char* info_language_standard_default = "INFO" ":" "standard_default["
 #if CXX_STD > 202002L
   "23"
 #elfif CXX_STD > 201703L
@@ -45,6 +45,14 @@ const char* info_language_dialect_default = "INFO" ":" "dialect_default["
 #endif
 "]";
 
+const char* info_language_extensions_default = "INFO" ":" "extensions_default["
+#if (defined(__clang__) || defined(__GNUC__)) && !defined(__STRICT_ANSI__)
+  "ON"
+#else
+  "OFF"
+#endif
+"]";
+
 /*--------------------------------------------------------------------------*/
 
 int main(int argc, char* argv[])
@@ -64,7 +72,8 @@ int main(int argc, char* argv[])
 #ifdef SIMULATE_VERSION_MAJOR
   require += info_simulate_version[argc];
 #endif
-  require += info_language_dialect_default[argc];
+  require += info_language_standard_default[argc];
+  require += info_language_extensions_default[argc];
   (void)argv;
   return require;
 }
index 70e8579..a6d824f 100644 (file)
@@ -189,6 +189,15 @@ foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
   endif()
 endforeach()
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_OBJCXX_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_OBJCXX_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 # add the flags to the cache based
 # on the initial values computed in the platform/*.cmake files
 # use _INIT variables so that this only happens the first time
index 8f0909c..ecad1d5 100644 (file)
@@ -70,6 +70,15 @@ set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O")
 set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g")
 set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize")
 
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  if(NOT DEFINED CMAKE_Swift_LINK_WHAT_YOU_USE_FLAG)
+    set(CMAKE_Swift_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+  endif()
+  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+  endif()
+endif()
+
 cmake_initialize_per_config_variable(CMAKE_Swift_FLAGS "Swift Compiler Flags")
 
 # NOTE(compnerd) we do not have an object compile rule since we build the objects as part of the link step
index f25788d..579f83f 100644 (file)
@@ -17,11 +17,18 @@ unset(CMAKE_Fortran_COMPILER_WORKS CACHE)
 
 # Try to identify the ABI and configure it into CMakeFortranCompiler.cmake
 include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
-CMAKE_DETERMINE_COMPILER_ABI(Fortran ${CMAKE_ROOT}/Modules/CMakeFortranCompilerABI.F)
+CMAKE_DETERMINE_COMPILER_ABI(Fortran ${CMAKE_ROOT}/Modules/CMakeFortranCompilerABI.F90)
 if(CMAKE_Fortran_ABI_COMPILED)
   # The compiler worked so skip dedicated test below.
   set(CMAKE_Fortran_COMPILER_WORKS TRUE)
+  set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 1)
   message(STATUS "Check for working Fortran compiler: ${CMAKE_Fortran_COMPILER} - skipped")
+else()
+  cmake_determine_compiler_abi(Fortran ${CMAKE_ROOT}/Modules/CMakeFortranCompilerABI.F)
+  if(CMAKE_Fortran_ABI_COMPILED)
+    set(CMAKE_Fortran_COMPILER_WORKS TRUE)
+    message(STATUS "Check for working Fortran 77 compiler: ${CMAKE_Fortran_COMPILER} - skipped")
+  endif()
 endif()
 
 # This file is used by EnableLanguage in cmGlobalGenerator to
index 5acd806..ecbfa7f 100644 (file)
@@ -10,7 +10,7 @@ if(CMAKE_HIP_COMPILER_FORCED)
 endif()
 
 set(__CMAKE_HIP_FLAGS "${CMAKE_HIP_FLAGS}")
-string(APPEND CMAKE_HIP_FLAGS "--cuda-host-only")
+string(APPEND CMAKE_HIP_FLAGS " --cuda-host-only")
 
 include(CMakeTestCompilerCommon)
 
index 2e68770..85108db 100644 (file)
@@ -439,6 +439,7 @@ set(_CPACK_IFW_PREFIXES
   "QtIFW-")
 
 set(_CPACK_IFW_VERSIONS
+  "4.2"
   "4.1"
   "4.0"
   "3.2"
index b4da4fa..7b13c3a 100644 (file)
@@ -25,7 +25,7 @@ Check if a symbol exists as a function, variable, or macro in ``C++``.
   as a function or variable then the symbol must also be available for
   linking.  If the symbol is a type, enum value, or C++ template it will
   not be recognized: consider using the :module:`CheckTypeSize`
-  or :module:`CheckCXXSourceCompiles` module instead.
+  or :module:`CheckSourceCompiles` module instead.
 
 .. note::
 
index ad72e2f..8f1ca9d 100644 (file)
@@ -20,6 +20,12 @@ Check if a Fortran function exists.
   ``<result>``
     variable to store the result; will be created as an internal cache variable.
 
+.. note::
+
+  This command does not detect functions in Fortran modules. In general it is
+  recommended to use :module:`CheckSourceCompiles` instead to determine if a
+  Fortran function or subroutine is available.
+
 The following variables may be set before calling this macro to modify
 the way the check is run:
 
index 559c103..52f707c 100644 (file)
@@ -46,7 +46,7 @@ macro(check_language lang)
     file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang})
 
     set(extra_compiler_variables)
-    if(${lang} STREQUAL CUDA)
+    if(${lang} STREQUAL CUDA AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
       set(extra_compiler_variables "set(CMAKE_CUDA_HOST_COMPILER \\\"\${CMAKE_CUDA_HOST_COMPILER}\\\")")
     endif()
 
index 28ac2e3..e85e43e 100644 (file)
@@ -41,6 +41,10 @@ include_guard(GLOBAL)
 
 include(CMakeCheckCompilerFlagCommonPatterns)
 
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
+cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST
+
 function(CHECK_LINKER_FLAG _lang _flag _var)
   get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
   if (NOT _lang IN_LIST _supported_languages)
@@ -82,3 +86,5 @@ function(CHECK_LINKER_FLAG _lang _flag _var)
   endforeach()
   set(${_var} "${${_var}}" PARENT_SCOPE)
 endfunction()
+
+cmake_policy(POP)
index f8ca584..48ee3c4 100644 (file)
@@ -24,7 +24,7 @@ available and assumed to work.  If the header files declare the symbol
 as a function or variable then the symbol must also be available for
 linking (so intrinsics may not be detected).
 If the symbol is a type, enum value, or intrinsic it will not be recognized
-(consider using :module:`CheckTypeSize` or :module:`CheckCSourceCompiles`).
+(consider using :module:`CheckTypeSize` or :module:`CheckSourceCompiles`).
 If the check needs to be done in C++, consider using
 :module:`CheckCXXSymbolExists` instead.
 
index 0a64a8a..01c4cea 100644 (file)
@@ -2,6 +2,14 @@ include(Compiler/Clang-C)
 include(Compiler/ARMClang)
 __compiler_armclang(C)
 
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_C)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_C_DEPFILE_FORMAT gcc)
+  set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
+
 set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
 set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
 set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
index 5dfb401..045b783 100644 (file)
@@ -1,3 +1,11 @@
 include(Compiler/Clang-CXX)
 include(Compiler/ARMClang)
 __compiler_armclang(CXX)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_CXX)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+  set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
index 7c97969..28be1df 100644 (file)
@@ -47,17 +47,9 @@ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
     set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
 endif()
 
-if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0)
-  set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++20")
-  set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++20")
-elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0)
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0)
   set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++2a")
   set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++2a")
 endif()
 
-if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0)
-  set(CMAKE_CXX23_STANDARD_COMPILE_OPTION "-std=c++2b")
-  set(CMAKE_CXX23_EXTENSION_COMPILE_OPTION "-std=gnu++2b")
-endif()
-
 __compiler_check_default_language_standard(CXX 4.0 98)
index c86af98..2f220d4 100644 (file)
@@ -38,20 +38,26 @@ macro(__compiler_check_default_language_standard lang stdver1 std1)
   # support for language standards, then don't bother.
   if (CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL "${stdver1}")
     if (NOT CMAKE_${lang}_COMPILER_FORCED)
-      if (NOT CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT)
-        message(FATAL_ERROR "CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT should be set for ${CMAKE_${lang}_COMPILER_ID} (${CMAKE_${lang}_COMPILER}) version ${CMAKE_${lang}_COMPILER_VERSION}")
+      if (NOT CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT OR NOT DEFINED CMAKE_${lang}_EXTENSIONS_COMPUTED_DEFAULT)
+        message(FATAL_ERROR "CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT and CMAKE_${lang}_EXTENSIONS_COMPUTED_DEFAULT should be set for ${CMAKE_${lang}_COMPILER_ID} (${CMAKE_${lang}_COMPILER}) version ${CMAKE_${lang}_COMPILER_VERSION}")
       endif ()
       set(CMAKE_${lang}_STANDARD_DEFAULT ${CMAKE_${lang}_STANDARD_COMPUTED_DEFAULT})
+      set(CMAKE_${lang}_EXTENSIONS_DEFAULT ${CMAKE_${lang}_EXTENSIONS_COMPUTED_DEFAULT})
     else ()
       list(REVERSE __std_ver_pairs)
       foreach (__std_ver_pair IN LISTS __std_ver_pairs)
         string(REGEX MATCH "([^ ]+) (.+)" __std_ver_pair "${__std_ver_pair}")
         set(__stdver ${CMAKE_MATCH_1})
         set(__std ${CMAKE_MATCH_2})
-        if (CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL __stdver AND
-          NOT DEFINED CMAKE_${lang}_STANDARD_DEFAULT)
-          # Compiler id was forced so just guess the default standard level.
-          set(CMAKE_${lang}_STANDARD_DEFAULT ${__std})
+        # Compiler id was forced so just guess the defaults.
+        if (CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL __stdver)
+          if(NOT DEFINED CMAKE_${lang}_EXTENSIONS_DEFAULT)
+            # Currently known compilers default to enabling extensions.
+            set(CMAKE_${lang}_EXTENSIONS_DEFAULT ON)
+          endif()
+          if(NOT DEFINED CMAKE_${lang}_STANDARD_DEFAULT)
+            set(CMAKE_${lang}_STANDARD_DEFAULT ${__std})
+          endif()
         endif ()
         unset(__std)
         unset(__stdver)
index cf493d7..1b765ad 100644 (file)
@@ -9,6 +9,7 @@ endif()
 if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
   set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
   set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+  set(CMAKE_C_INCLUDE_WHAT_YOU_USE_DRIVER_MODE "cl")
   if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
       AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
       AND CMAKE_DEPFILE_FLAGS_C)
index 98828e0..84b05d7 100644 (file)
@@ -22,6 +22,7 @@ endif()
 
 if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
   set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+  set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE_DRIVER_MODE "cl")
   if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
       AND CMAKE_GENERATOR MATCHES "Makefiles"
       AND CMAKE_DEPFILE_FLAGS_CXX)
index e3ca16e..bae0fbd 100644 (file)
@@ -1,57 +1,45 @@
-# This file is processed when the IAR compiler is used for an assembler file
+# This file is processed when the IAR Assembler is used
 
 include(Compiler/IAR)
 
-if("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
-  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
-  __compiler_iar_ilink(ASM)
-  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
 
-elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
-  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
-  __compiler_iar_ilink(ASM)
-  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+set(_CMAKE_IAR_ITOOLS "ARM" "RH850"  "RL78" "RX" "RISC-V" "STM8")
+set(_CMAKE_IAR_XTOOLS "AVR" "MSP430" "V850" "8051")
 
-elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850")
-  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
-  __compiler_iar_ilink(ASM)
-  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
-
-elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78")
-  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
-  __compiler_iar_ilink(ASM)
-  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
-
-elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RISC-V")
-  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
-  __compiler_iar_ilink(ASM)
-  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+set(_CMAKE_IAR_ASM_SILENT   "RH850"  "RL78" "RX" "RISC-V" "STM8")
+if("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" IN_LIST _CMAKE_IAR_ASM_SILENT)
+  set(_CMAKE_IAR_SILENCER_FLAG " --silent")
+else()
+  set(_CMAKE_IAR_SILENCER_FLAG " -S")
+endif()
 
-elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
-  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
-  __compiler_iar_xlink(ASM)
-  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s90;asm;msa)
+string(APPEND CMAKE_ASM_FLAGS_INIT " ")
+string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r")
+string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
+string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG")
 
-elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430")
-  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
-  __compiler_iar_xlink(ASM)
-  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s43;asm;msa)
+set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> ${_CMAKE_IAR_SILENCER_FLAG} <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
 
-elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "V850")
-  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
-  __compiler_iar_xlink(ASM)
-  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s85;asm;msa)
+if("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" IN_LIST _CMAKE_IAR_ITOOLS)
+  __compiler_iar_ilink(ASM)
+  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa;S)
 
-elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "8051")
-  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" IN_LIST _CMAKE_IAR_XTOOLS)
   __compiler_iar_xlink(ASM)
-  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s51;asm;msa)
-
-elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "STM8")
-  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
-  __compiler_iar_ilink(ASM)
-  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+  # AVR=s90, MSP430=s43, V850=s85, 8051=s51
+  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s90;s43;s85;s51;asm;msa)
 
 else()
   message(FATAL_ERROR "CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID not detected. This should be automatic.")
+
 endif()
+
+unset(_CMAKE_IAR_ITOOLS)
+unset(_CMAKE_IAR_XTOOLS)
+unset(_CMAKE_IAR_ASM_SILENT)
+unset(_CMAKE_IAR_SILENCER_FLAG)
+
+cmake_policy(POP)
index 054ee74..0ef1a2a 100644 (file)
@@ -1,54 +1,61 @@
-# This file is processed when the IAR compiler is used for a C file
-
+# This file is processed when the IAR C Compiler is used
+#
+# C Language Specification support
+#  - Newer versions of the IAR C Compiler require the --c89 flag to build a file under the C90 standard.
+#  - Earlier versions of the compiler had C90 by default, not requiring the backward-compatibility flag.
+#
+# The IAR Language Extensions
+#  - The IAR Language Extensions can be enabled by -e flag
+#
 include(Compiler/IAR)
 include(Compiler/CMakeCommonCompilerMacros)
 
-# Common
-if(NOT CMAKE_C_COMPILER_VERSION)
+if(NOT DEFINED CMAKE_C_COMPILER_VERSION)
   message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION not detected.  This should be automatic.")
 endif()
 
+# Unused after CMP0128
 set(CMAKE_C_EXTENSION_COMPILE_OPTION -e)
 
 if(CMAKE_C_COMPILER_VERSION_INTERNAL VERSION_GREATER 7)
   set(CMAKE_C90_STANDARD_COMPILE_OPTION --c89)
   set(CMAKE_C90_EXTENSION_COMPILE_OPTION --c89 -e)
-  set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
-  set(CMAKE_C99_EXTENSION_COMPILE_OPTION -e)
 else()
   set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
   set(CMAKE_C90_EXTENSION_COMPILE_OPTION -e)
 endif()
 
-if(CMAKE_C_COMPILER_VERSION_INTERNAL VERSION_GREATER 8)
-  set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
-  set(CMAKE_C11_EXTENSION_COMPILE_OPTION -e)
-endif()
+set(CMAKE_C${CMAKE_C_STANDARD_COMPUTED_DEFAULT}_STANDARD_COMPILE_OPTION "")
+set(CMAKE_C${CMAKE_C_STANDARD_COMPUTED_DEFAULT}_EXTENSION_COMPILE_OPTION -e)
 
 # Architecture specific
 if("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
-  if(CMAKE_C_COMPILER_VERSION_INTERNAL VERSION_LESS 7)
-    # IAR ARM 4.X uses xlink.exe, detection is not yet implemented
-    message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION = ${CMAKE_C_COMPILER_VERSION} not supported by CMake.")
+  if (CMAKE_C_COMPILER_VERSION VERSION_LESS 5)
+    # IAR C Compiler for Arm prior version 5.xx uses XLINK. Support in CMake is not implemented.
+    message(FATAL_ERROR "IAR C Compiler for Arm version ${CMAKE_C_COMPILER_VERSION} not supported by CMake.")
   endif()
   __compiler_iar_ilink(C)
-  __compiler_check_default_language_standard(C 1.10 90 6.10 99 8.10 11)
+  __compiler_check_default_language_standard(C 5.10 90 6.10 99 8.10 11 8.40 17)
 
 elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
   __compiler_iar_ilink(C)
-  __compiler_check_default_language_standard(C 1.10 90 2.10 99 4.10 11)
+  __compiler_check_default_language_standard(C 1.10 90 2.10 99 4.10 11 4.20 17)
 
 elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850")
   __compiler_iar_ilink(C)
-  __compiler_check_default_language_standard(C 1.10 90 1.10 99 2.10 11)
+  __compiler_check_default_language_standard(C 1.10 90 1.10 99 2.10 11 2.21 17)
 
 elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78")
+  if(CMAKE_C_COMPILER_VERSION VERSION_LESS 2)
+    # IAR C Compiler for RL78 prior version 2.xx uses XLINK. Support in CMake is not implemented.
+    message(FATAL_ERROR "IAR C Compiler for RL78 version ${CMAKE_C_COMPILER_VERSION} not supported by CMake.")
+  endif()
   __compiler_iar_ilink(C)
-  __compiler_check_default_language_standard(C 1.10 90 1.10 99 4.10 11)
+  __compiler_check_default_language_standard(C 2.10 90 2.10 99 4.10 11 4.20 17)
 
 elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RISCV")
   __compiler_iar_ilink(C)
-  __compiler_check_default_language_standard(C 1.10 90 1.10 99 1.10 11)
+  __compiler_check_default_language_standard(C 1.10 90 1.10 99 1.10 11 1.21 17)
 
 elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
   __compiler_iar_xlink(C)
index d93b272..a3f1dbc 100644 (file)
@@ -1,63 +1,65 @@
-# This file is processed when the IAR compiler is used for a C++ file
-
+# This file is processed when the IAR C++ Compiler is used
+#
+# C++ Language Specification support
+#  - Newer versions of the IAR C++ Compiler require the --c++ flag to build a C++ file.
+#    Earlier versions for non-ARM architectures provided Embedded C++, enabled with the --eec++ flag.
+#
+# The IAR Language Extensions
+#  - The IAR Language Extensions can be enabled by -e flag
+#
 include(Compiler/IAR)
 include(Compiler/CMakeCommonCompilerMacros)
 
-# Common
-if(NOT CMAKE_CXX_COMPILER_VERSION)
+if(NOT DEFINED CMAKE_CXX_COMPILER_VERSION)
   message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION not detected. This should be automatic.")
 endif()
 
+# Whenever needed, override this default behavior using CMAKE_IAR_CXX_FLAG in your toolchain file.
 if(NOT CMAKE_IAR_CXX_FLAG)
-  # The --c++ flag was introduced in platform version 9 for all architectures except ARM where it was introduced already in version 7
-  if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 8 OR
-    (CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 6 AND "${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM") )
-    set(CMAKE_IAR_CXX_FLAG --c++)
+  set(_CMAKE_IAR_MODERNCXX_LIST 14 17)
+  if(${CMAKE_CXX_STANDARD_COMPUTED_DEFAULT} IN_LIST _CMAKE_IAR_MODERNCXX_LIST OR
+     ("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM" AND ${CMAKE_CXX_STANDARD_COMPUTED_DEFAULT} EQUAL 98))
+    string(PREPEND CMAKE_CXX_FLAGS "--c++ ")
   else()
-    set(CMAKE_IAR_CXX_FLAG --eec++)
+    string(PREPEND CMAKE_CXX_FLAGS "--eec++ ")
   endif()
+  unset(_CMAKE_IAR_MODERNCXX_LIST)
 endif()
 
-set(CMAKE_CXX_EXTENSION_COMPILE_OPTION -e)
+set(CMAKE_CXX_STANDARD_COMPILE_OPTION "")
+set(CMAKE_CXX_EXTENSION_COMPILE_OPTION -e) # Unused after CMP0128
 
-if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 7)
-  set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
-  set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION -e)
-  set(CMAKE_CXX03_STANDARD_COMPILE_OPTION "")
-  set(CMAKE_CXX03_EXTENSION_COMPILE_OPTION -e)
-endif()
-
-if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 8)
-  set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
-  set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION -e)
-  set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "")
-  set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION -e)
-endif()
+set(CMAKE_CXX${CMAKE_CXX_STANDARD_COMPUTED_DEFAULT}_STANDARD_COMPILE_OPTION "")
+set(CMAKE_CXX${CMAKE_CXX_STANDARD_COMPUTED_DEFAULT}_EXTENSION_COMPILE_OPTION -e)
 
 # Architecture specific
 if("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM")
-  if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_LESS 7)
-    # IAR ARM 4.X uses xlink.exe, detection is not yet implemented
-    message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION = ${CMAKE_C_COMPILER_VERSION} not supported by CMake.")
+  if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5)
+    # IAR C++ Compiler for Arm prior version 5.xx uses XLINK. Support in CMake is not implemented.
+    message(FATAL_ERROR "IAR C++ Compiler for Arm version ${CMAKE_CXX_COMPILER_VERSION} not supported by CMake.")
   endif()
   __compiler_iar_ilink(CXX)
-  __compiler_check_default_language_standard(CXX 6.10 98 8.10 14)
+  __compiler_check_default_language_standard(CXX 5.10 98 8.10 14 8.40 17)
 
 elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX")
   __compiler_iar_ilink(CXX)
-  __compiler_check_default_language_standard(CXX 2.10 98 4.10 14)
+  __compiler_check_default_language_standard(CXX 2.10 98 4.10 14 4.20 17)
 
 elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850")
   __compiler_iar_ilink(CXX)
-  __compiler_check_default_language_standard(CXX 1.10 98 2.10 14)
+  __compiler_check_default_language_standard(CXX 1.10 98 2.10 14 2.21 17)
 
 elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78")
+  if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2)
+    # # IAR C++ Compiler for RL78 prior version 2.xx uses XLINK. Support in CMake is not implemented.
+    message(FATAL_ERROR "IAR C++ Compiler for RL78 version ${CMAKE_CXX_COMPILER_VERSION} not supported by CMake.")
+  endif()
   __compiler_iar_ilink(CXX)
-  __compiler_check_default_language_standard(CXX 1.10 98 4.10 14)
+  __compiler_check_default_language_standard(CXX 2.10 98 4.10 14 4.20 17)
 
 elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RISCV")
   __compiler_iar_ilink(CXX)
-  __compiler_check_default_language_standard(CXX 1.10 98 1.10 14)
+  __compiler_check_default_language_standard(CXX 1.10 98 1.10 14 1.21 17)
 
 elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR")
   __compiler_iar_xlink(CXX)
index 443b09c..b03fd1f 100644 (file)
@@ -1,28 +1,26 @@
-# IAR Systems compiler for ARM embedded systems.
-#   http://www.iar.com
-#   http://supp.iar.com/FilesPublic/UPDINFO/004916/arm/doc/EWARM_DevelopmentGuide.ENU.pdf
+# IAR C/C++ Compiler (https://www.iar.com)
+# CPU <arch> supported in CMake: 8051, Arm, AVR, MSP430, RH850, RISC-V, RL78, RX and V850
 #
-# __IAR_SYSTEMS_ICC__ An integer that identifies the IAR compiler platform:
-#                       9 and higher means C11 and C++14 as language default
-#                       8 means C99 and C++03 as language default
-#                       7 and lower means C89 and EC++ as language default.
-# __ICCARM__          An integer that is set to 1 when the code is compiled with the IAR C/C++ Compiler for ARM
-# __VER__             An integer that identifies the version number of the IAR compiler in use. For example,
-#                     version 5.11.3 is returned as 5011003.
+# IAR C/C++ Compiler for <arch> internal integer symbols used in CMake:
 #
-# IAR Systems Compiler for AVR embedded systems
-#  http://supp.iar.com/FilesPublic/UPDINFO/007051/ew/doc/EWAVR_CompilerReference.pdf
+# __IAR_SYSTEMS_ICC__
+#           Provides the compiler internal platform version
+# __ICC<arch>__
+#           Provides 1 for the current <arch> in use
+# __VER__
+#           Provides the current version in use
+#            The semantic version of the compiler is architecture-dependent
+#            When <arch> is ARM:
+#               CMAKE_<LANG>_COMPILER_VERSION_MAJOR = (__VER__ / 1E6)
+#               CMAKE_<LANG>_COMPILER_VERSION_MINOR = (__VER__ / 1E3) % 1E3
+#               CMAKE_<LANG>_COMPILER_VERSION_PATCH = (__VER__ % 1E3)
+#            When <arch> is non-ARM:
+#               CMAKE_<LANG>_COMPILER_VERSION_MAJOR = (__VER__ / 1E2)
+#               CMAKE_<LANG>_COMPILER_VERSION_MINOR = (__VER__ - ((__VER__/ 1E2) * 1E2))
+#               CMAKE_<LANG>_COMPILER_VERSION_PATCH = (__SUBVERSION__)
+# __SUBVERSION__
+#           Provides the version's patch level for non-ARM <arch>
 #
-# __IAR_SYSTEMS_ICC__ An integer that identifies the IAR compiler platform.
-# __ICCAVR__          An integer that is set to 1 when the code is compiled with the IAR C/C++ Compiler for AVR
-# __VER__             An integer that identifies the version number of the IAR compiler in use.
-#                     The value is calculated by (100 * VERSION_MAJOR + VERSION_MINOR). For example the version
-#                     3.34 is given as 334
-# __SUBVERSION__      An integer that identifies the subversion number of the compiler version number
-#                     for example 3 in 1.2.3.4.  THis is used as the patch version, as seen when running iccavr
-#                     from the command line
-#
-
 set(_compiler_id_pp_test "defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)")
 
 set(_compiler_id_version_compute "
index 2200a21..53456f5 100644 (file)
@@ -1,47 +1,15 @@
-# 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://gitlab.kitware.com/cmake/cmake/-/issues/10176
-# It also contains additional links and information.
-# See USER GUIDES -> C/C++ Development Guide and ReleaseNotes for EWARM:
-# version 6.30.8: http://supp.iar.com/FilesPublic/UPDINFO/006607/arm/doc/infocenter/index.ENU.html
-# version 7.60.1: http://supp.iar.com/FilesPublic/UPDINFO/011006/arm/doc/infocenter/index.ENU.html
-# version 8.10.1: http://netstorage.iar.com/SuppDB/Public/UPDINFO/011854/arm/doc/infocenter/index.ENU.html
-
-# The IAR internal compiler platform generations (Predefined symbol __IAR_SYSTEMS_ICC__):
-#  9 and higher means C11 and C++14 as language default (EWARM v8.x, EWRX v4.x and higher)
-#  8 means C99 and C++03 as language default (EWARM v6.x, v7.x. EWRX v2.x, 3.x)
-#  7 and lower means C89 and EC++ as language default. (EWARM v5.x and lower)
-
-# C/C++ Standard versions
-#
-# IAR typically only supports one C and C++ Standard version,
-# the exception is C89 which is always supported and can be selected
-# if its not the default
-#
-# C++ is trickier, there were historically 3 switches,
-# and some IAR versions support multiple of those.
-# they are --eec++, --ec++ and --c++ and where used to
-# enable various language features like exceptions
-#
-# recent versions only have --c++ for full support
-# but can choose to disable features with further arguments
+# This file is processed when the IAR C/C++ Compiler is used
 #
-# C/C++ Standard compliance
+# CPU <arch> supported in CMake: 8051, Arm, AVR, MSP430, RH850, RISC-V, RL78, RX and V850
 #
-# IAR has 3 modes: default, strict and extended
-# the extended mode is needed for popular libraries like CMSIS
+# The compiler user documentation is architecture-dependent
+# and it can found with the product installation under <arch>/doc/{EW,BX}<arch>_DevelopmentGuide.ENU.pdf
 #
-# "Silent" Operation
 #
-# this really is different to most programs I know.
-# nothing meaningful from the operation is lost, just some redundant
-# code and data size printouts (that can be inspected with common tools).
-
-# This module is shared by multiple languages; use include blocker.
 include_guard()
 
 macro(__compiler_iar_ilink lang)
-  set(CMAKE_EXECUTABLE_SUFFIX_${lang} ".elf")
+  set(CMAKE_EXECUTABLE_SUFFIX ".elf")
   set(CMAKE_${lang}_OUTPUT_EXTENSION ".o")
   if (${lang} STREQUAL "C" OR ${lang} STREQUAL "CXX")
     set(CMAKE_${lang}_COMPILE_OBJECT             "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
@@ -58,14 +26,6 @@ macro(__compiler_iar_ilink lang)
     string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Oh -r -DNDEBUG")
   endif()
 
-  if (${lang} STREQUAL "ASM")
-    string(APPEND CMAKE_ASM_FLAGS_INIT " ")
-    string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r")
-    string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
-    string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
-    string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG")
-  endif()
-
   set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_LINKER> --silent <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
   set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "<CMAKE_AR> <TARGET> --create <LINK_FLAGS> <OBJECTS>")
   set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> <TARGET> --create <LINK_FLAGS> <OBJECTS>")
@@ -74,7 +34,7 @@ macro(__compiler_iar_ilink lang)
 endmacro()
 
 macro(__compiler_iar_xlink lang)
-  set(CMAKE_EXECUTABLE_SUFFIX_${lang} ".bin")
+  set(CMAKE_EXECUTABLE_SUFFIX ".bin")
   if (${lang} STREQUAL "C" OR ${lang} STREQUAL "CXX")
 
     set(CMAKE_${lang}_COMPILE_OBJECT             "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
@@ -91,14 +51,6 @@ macro(__compiler_iar_xlink lang)
     string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Oh -r -DNDEBUG")
   endif()
 
-  if (${lang} STREQUAL "ASM")
-    string(APPEND CMAKE_ASM_FLAGS_INIT " ")
-    string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r")
-    string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
-    string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
-    string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG")
-  endif()
-
   set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_LINKER> -S <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
   set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "<CMAKE_AR> <TARGET> <LINK_FLAGS> <OBJECTS>")
   set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> <TARGET> <LINK_FLAGS> <OBJECTS>")
index ead9069..9884b58 100644 (file)
@@ -17,6 +17,7 @@ if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
 
   set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
   set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+  set(CMAKE_C_INCLUDE_WHAT_YOU_USE_DRIVER_MODE "cl")
 
   if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 16.0.0)
     set(CMAKE_C11_STANDARD_COMPILE_OPTION "-Qstd=c11")
index 37f339a..7c9cca9 100644 (file)
@@ -16,6 +16,7 @@ endif()
 if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
 
   set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+  set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE_DRIVER_MODE "cl")
 
   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0.0)
     set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-Qstd=c++20")
index d69d064..d7346f6 100644 (file)
@@ -4,6 +4,7 @@ __compiler_intel_llvm(C)
 if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
   set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
   set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+  set(CMAKE_C_INCLUDE_WHAT_YOU_USE_DRIVER_MODE "cl")
   if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
       AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
       AND CMAKE_DEPFILE_FLAGS_C)
index 9799888..cae1f11 100644 (file)
@@ -4,6 +4,7 @@ __compiler_intel_llvm(CXX)
 if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
   set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TP)
   set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+  set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE_DRIVER_MODE "cl")
   if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
       AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
       AND CMAKE_DEPFILE_FLAGS_CXX)
index 9a5104b..a53df46 100644 (file)
@@ -11,6 +11,22 @@ if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.27)
   set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std:c11")
   set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std:c11")
 
+  if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.28)
+    set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+    set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+    set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+    set(CMAKE_C17_STANDARD_COMPILE_OPTION "-std:c17")
+    set(CMAKE_C17_EXTENSION_COMPILE_OPTION "-std:c17")
+  else()
+    # Special case for 19.27 (VS 16.7): C11 has partial support.
+    macro(cmake_record_c_compile_features)
+      _has_compiler_features_c(90)
+      _has_compiler_features_c(99)
+      list(APPEND CMAKE_C11_COMPILE_FEATURES c_std_11)
+      set(_result 0) # expected by cmake_determine_compile_features
+    endmacro()
+  endif()
+
   __compiler_check_default_language_standard(C 19.27 99)
 else()
   # MSVC has no specific options to set C language standards, but set them as
@@ -25,41 +41,42 @@ else()
 
   # There is no meaningful default for this
   set(CMAKE_C_STANDARD_DEFAULT "")
+
+  # There are no C compiler modes so we hard-code the known compiler supported
+  # features. Override the default macro for this special case.  Pretend that
+  # all language standards are available so that at least compilation
+  # can be attempted.
+  macro(cmake_record_c_compile_features)
+    list(APPEND CMAKE_C_COMPILE_FEATURES
+      c_std_90
+      c_std_99
+      c_std_11
+      c_std_17
+      c_std_23
+      c_function_prototypes
+      )
+    list(APPEND CMAKE_C90_COMPILE_FEATURES c_std_90 c_function_prototypes)
+    list(APPEND CMAKE_C99_COMPILE_FEATURES c_std_99)
+    list(APPEND CMAKE_C11_COMPILE_FEATURES c_std_11)
+    if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 14.0)
+      list(APPEND CMAKE_C_COMPILE_FEATURES c_variadic_macros)
+      list(APPEND CMAKE_C99_COMPILE_FEATURES c_variadic_macros)
+    endif()
+    set(_result 0) # expected by cmake_determine_compile_features
+  endmacro()
 endif()
 
 set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
 set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
-
-# There are no C compiler modes so we hard-code the known compiler supported
-# features. Override the default macro for this special case.  Pretend that
-# all language standards are available so that at least compilation
-# can be attempted.
-macro(cmake_record_c_compile_features)
-  list(APPEND CMAKE_C_COMPILE_FEATURES
-    c_std_90
-    c_std_99
-    c_std_11
-    c_function_prototypes
-    )
-  list(APPEND CMAKE_C90_COMPILE_FEATURES c_std_90 c_function_prototypes)
-  list(APPEND CMAKE_C99_COMPILE_FEATURES c_std_99)
-  list(APPEND CMAKE_C11_COMPILE_FEATURES c_std_11)
-  if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 14.0)
-    list(APPEND CMAKE_C_COMPILE_FEATURES c_variadic_macros)
-    list(APPEND CMAKE_C99_COMPILE_FEATURES c_variadic_macros)
-  endif()
-  if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.27)
-    list(APPEND CMAKE_C_COMPILE_FEATURES c_restrict)
-    list(APPEND CMAKE_C99_COMPILE_FEATURES c_restrict)
-  endif()
-  if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.28)
-    list(APPEND CMAKE_C_COMPILE_FEATURES c_static_assert)
-    list(APPEND CMAKE_C11_COMPILE_FEATURES c_static_assert)
-  endif()
-  set(_result 0) # expected by cmake_determine_compile_features
-endmacro()
+set(CMAKE_C_INCLUDE_WHAT_YOU_USE_DRIVER_MODE "cl")
 
 # /JMC "Just My Code" is only supported by MSVC 19.05 onward.
 if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
   set(CMAKE_C_COMPILE_OPTIONS_JMC "-JMC")
 endif()
+
+# The `/external:I` flag was made non-experimental in 19.29.30036.3.
+if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30036.3)
+  set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-external:I ")
+  set(_CMAKE_INCLUDE_SYSTEM_FLAG_C_WARNING "-external:W0 ")
+endif ()
index 5df5c1e..bcaec69 100644 (file)
@@ -4,6 +4,7 @@
 include(Compiler/CMakeCommonCompilerMacros)
 
 set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE_DRIVER_MODE "cl")
 
 if ((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.0.24215.1 AND
      CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) OR
@@ -80,3 +81,9 @@ endif()
 if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
   set(CMAKE_CXX_COMPILE_OPTIONS_JMC "-JMC")
 endif()
+
+# The `/external:I` flag was made non-experimental in 19.29.30036.3.
+if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30036.3)
+  set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-external:I ")
+  set(_CMAKE_INCLUDE_SYSTEM_FLAG_CXX_WARNING "-external:W0 ")
+endif ()
index 7048670..b51bb43 100644 (file)
@@ -12,4 +12,5 @@ include(Compiler/PGI)
 
 macro(__compiler_nvhpc lang)
   # Logic specific to NVHPC.
+  set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ")
 endmacro()
index 4f8b90b..d111be9 100644 (file)
@@ -26,7 +26,7 @@ macro(__compiler_pgi lang)
   endif()
 
   set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
-  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG ",")
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
 
   set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
   if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL ppc64le AND (NOT CMAKE_HOST_WIN32 OR CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 16.3))
index ed5e847..fba74ff 100644 (file)
@@ -6,6 +6,9 @@
     <Keyword>Win32Proj</Keyword>
     @id_system@
     @id_system_version@
+    @id_TargetFrameworkVersion@
+    @id_TargetFrameworkIdentifier@
+    @id_TargetFrameworkTargetsVersion@
     @id_WindowsTargetPlatformVersion@
     @id_WindowsSDKDesktopARMSupport@
   </PropertyGroup>
index 9e25bee..e49faae 100644 (file)
@@ -224,14 +224,14 @@ External Project Definition
       ``TLS_CAINFO <file>``
         Specify a custom certificate authority file to use if ``TLS_VERIFY``
         is enabled. If this option is not specified, the value of the
-        ``CMAKE_TLS_CAINFO`` variable will be used instead (see
+        :variable:`CMAKE_TLS_CAINFO` variable will be used instead (see
         :command:`file(DOWNLOAD)`)
 
       ``NETRC <level>``
         .. versionadded:: 3.11
 
         Specify whether the ``.netrc`` file is to be used for operation.
-        If this option is not specified, the value of the ``CMAKE_NETRC``
+        If this option is not specified, the value of the :variable:`CMAKE_NETRC`
         variable will be used instead (see :command:`file(DOWNLOAD)`)
         Valid levels are:
 
@@ -251,8 +251,8 @@ External Project Definition
 
         Specify an alternative ``.netrc`` file to the one in your home directory
         if the ``NETRC`` level is ``OPTIONAL`` or ``REQUIRED``. If this option
-        is not specified, the value of the ``CMAKE_NETRC_FILE`` variable will
-        be used instead (see :command:`file(DOWNLOAD)`)
+        is not specified, the value of the :variable:`CMAKE_NETRC_FILE` variable
+        will be used instead (see :command:`file(DOWNLOAD)`)
 
       .. versionadded:: 3.1
         Added support for `tbz2`, `.tar.xz`, `.txz`, and `.7z` extensions.
index bd82a90..be75689 100644 (file)
@@ -21,13 +21,14 @@ supported by the :module:`ExternalProject` module.  Whereas
 configure step to use the content in commands like :command:`add_subdirectory`,
 :command:`include` or :command:`file` operations.
 
-Content population details would normally be defined separately from the
-command that performs the actual population.  This separation ensures that
-all of the dependency details are defined before anything may try to use those
-details to populate content.  This is particularly important in more complex
-project hierarchies where dependencies may be shared between multiple projects.
+Content population details should be defined separately from the command that
+performs the actual population.  This separation ensures that all the
+dependency details are defined before anything might try to use them to
+populate content.  This is particularly important in more complex project
+hierarchies where dependencies may be shared between multiple projects.
 
-The following shows a typical example of declaring content details:
+The following shows a typical example of declaring content details for some
+dependencies and then ensuring they are populated with a separate call:
 
 .. code-block:: cmake
 
@@ -36,57 +37,67 @@ The following shows a typical example of declaring content details:
     GIT_REPOSITORY https://github.com/google/googletest.git
     GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
   )
+  FetchContent_Declare(
+    myCompanyIcons
+    URL      https://intranet.mycompany.com/assets/iconset_1.12.tar.gz
+    URL_HASH MD5=5588a7b18261c20068beabfb4f530b87
+  )
+
+  FetchContent_MakeAvailable(googletest secret_sauce)
+
+The :command:`FetchContent_MakeAvailable` command ensures the named
+dependencies have been populated, either by an earlier call or by populating
+them itself.  When performing the population, it will also add them to the
+main build, if possible, so that the main build can use the populated
+projects' targets, etc.  See the command's documentation for how these steps
+are performed.
+
+When using a hierarchical project arrangement, projects at higher levels in
+the hierarchy are able to override the declared details of content specified
+anywhere lower in the project hierarchy.  The first details to be declared
+for a given dependency take precedence, regardless of where in the project
+hierarchy that occurs.  Similarly, the first call that tries to populate a
+dependency "wins", with subsequent populations reusing the result of the
+first instead of repeating the population again.
+See the :ref:`Examples <fetch-content-examples>` which demonstrate
+this scenario.
 
-For most typical cases, populating the content can then be done with a single
-command like so:
+In some cases, the main project may need to have more precise control over
+the population, or it may be required to explicitly define the population
+steps in a way that cannot be captured by the declared details alone.
+For such situations, the lower level :command:`FetchContent_GetProperties` and
+:command:`FetchContent_Populate` commands can be used.  These lack the richer
+features provided by :command:`FetchContent_MakeAvailable` though, so their
+direct use should be considered a last resort.  The typical pattern of such
+custom steps looks like this:
 
 .. code-block:: cmake
 
-  FetchContent_MakeAvailable(googletest)
+  # NOTE: Where possible, prefer to use FetchContent_MakeAvailable()
+  #       instead of custom logic like this
 
-The above command not only populates the content, it also adds it to the main
-build (if possible) so that the main build can use the populated project's
-targets, etc.  In some cases, the main project may need to have more precise
-control over the population or may be required to explicitly define the
-population steps (e.g. if CMake versions earlier than 3.14 need to be
-supported).  The typical pattern of such custom steps looks like this:
+  # Check if population has already been performed
+  FetchContent_GetProperties(depname)
+  if(NOT depname_POPULATED)
+    # Fetch the content using previously declared details
+    FetchContent_Populate(depname)
 
-.. code-block:: cmake
+    # Set custom variables, policies, etc.
+    # ...
 
-  FetchContent_GetProperties(googletest)
-  if(NOT googletest_POPULATED)
-    FetchContent_Populate(googletest)
-    add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
+    # Bring the populated content into the build
+    add_subdirectory(${depname_SOURCE_DIR} ${depname_BINARY_DIR})
   endif()
 
-Regardless of which population method is used, when using the
-declare-populate pattern with a hierarchical project arrangement, projects at
-higher levels in the hierarchy are able to override the population details of
-content specified anywhere lower in the project hierarchy.  The ability to
-detect whether content has already been populated ensures that even if
-multiple child projects want certain content to be available, the first one
-to populate it wins.  The other child project can simply make use of the
-already available content instead of repeating the population for itself.
-See the :ref:`Examples <fetch-content-examples>` section which demonstrates
-this scenario.
-
 The ``FetchContent`` module also supports defining and populating
 content in a single call, with no check for whether the content has been
-populated elsewhere in the project already.  This is a more low level
-operation and would not normally be the way the module is used, but it is
-sometimes useful as part of implementing some higher level feature or to
-populate some content in CMake's script mode.
-
-.. versionchanged:: 3.14
-  ``FetchContent`` commands can access the terminal. This is necessary
-  for password prompts and real-time progress displays to work.
+populated elsewhere already.  This should not be done in projects, but may
+be appropriate for populating content in CMake's script mode.
+See :command:`FetchContent_Populate` for details.
 
 Commands
 ^^^^^^^^
 
-Declaring Content Details
-"""""""""""""""""""""""""
-
 .. command:: FetchContent_Declare
 
   .. code-block:: cmake
@@ -94,7 +105,7 @@ Declaring Content Details
     FetchContent_Declare(<name> <contentOptions>...)
 
   The ``FetchContent_Declare()`` function records the options that describe
-  how to populate the specified content, but if such details have already
+  how to populate the specified content.  If such details have already
   been recorded earlier in this project (regardless of where in the project
   hierarchy), this and all later calls for the same content ``<name>`` are
   ignored.  This "first to record, wins" approach is what allows hierarchical
@@ -110,7 +121,7 @@ Declaring Content Details
   projects needing that same content will use the same name, leading to
   the content being populated multiple times.
 
-  The ``<contentOptions>`` can be any of the download or update/patch options
+  The ``<contentOptions>`` can be any of the download, update or patch options
   that the :command:`ExternalProject_Add` command understands.  The configure,
   build, install and test steps are explicitly disabled and therefore options
   related to them will be ignored.  The ``SOURCE_SUBDIR`` option is an
@@ -146,47 +157,95 @@ Declaring Content Details
   than a branch or tag name.  A commit hash is more secure and helps to
   confirm that the downloaded contents are what you expected.
 
-Populating The Content
-""""""""""""""""""""""
+  .. versionchanged:: 3.14
+    Commands for the download, update or patch steps can access the terminal.
+    This may be needed for things like password prompts or real-time display
+    of command progress.
 
-For most common scenarios, population means making content available to the
-main build according to previously declared details for that dependency.
-There are two main patterns for populating content, one based on calling
-:command:`FetchContent_GetProperties` and
-:command:`FetchContent_Populate` for more precise control and the other on
-calling :command:`FetchContent_MakeAvailable` for a simpler, more automated
-approach.  The former generally follows this canonical pattern:
+  .. versionadded:: 3.22
+    The :variable:`CMAKE_TLS_VERIFY`, :variable:`CMAKE_TLS_CAINFO`,
+    :variable:`CMAKE_NETRC` and :variable:`CMAKE_NETRC_FILE` variables now
+    provide the defaults for their corresponding content options, just like
+    they do for :command:`ExternalProject_Add`. Previously, these variables
+    were ignored by the ``FetchContent`` module.
 
-.. _`fetch-content-canonical-pattern`:
+.. command:: FetchContent_MakeAvailable
 
-.. code-block:: cmake
+  .. versionadded:: 3.14
 
-  # Check if population has already been performed
-  FetchContent_GetProperties(<name>)
-  string(TOLOWER "<name>" lcName)
-  if(NOT ${lcName}_POPULATED)
-    # Fetch the content using previously declared details
-    FetchContent_Populate(<name>)
+  .. code-block:: cmake
 
-    # Set custom variables, policies, etc.
-    # ...
+    FetchContent_MakeAvailable(<name1> [<name2>...])
+
+  This command ensures that each of the named dependencies are populated and
+  potentially added to the build by the time it returns.  It iterates over
+  the list, and for each dependency, the following logic is applied:
+
+  * If the dependency has already been populated earlier in this run, set
+    the ``<lowercaseName>_POPULATED``, ``<lowercaseName>_SOURCE_DIR`` and
+    ``<lowercaseName>_BINARY_DIR`` variables in the same way as a call to
+    :command:`FetchContent_GetProperties`, then skip the remaining steps
+    below and move on to the next dependency in the list.
+
+  * Call :command:`FetchContent_Populate` to populate the dependency using
+    the details recorded by an earlier call to :command:`FetchContent_Declare`.
+    Halt with a fatal error if no such details have been recorded.
+    :variable:`FETCHCONTENT_SOURCE_DIR_<uppercaseName>` can be used to override
+    the declared details and use content provided at the specified location
+    instead.
+
+  * If the top directory of the populated content contains a ``CMakeLists.txt``
+    file, call :command:`add_subdirectory` to add it to the main build.
+    It is not an error for there to be no ``CMakeLists.txt`` file, which
+    allows the command to be used for dependencies that make downloaded
+    content available at a known location, but which do not need or support
+    being added directly to the build.
+
+    .. versionadded:: 3.18
+      The ``SOURCE_SUBDIR`` option can be given in the declared details to
+      look somewhere below the top directory instead (i.e. the same way that
+      ``SOURCE_SUBDIR`` is used by the :command:`ExternalProject_Add`
+      command).  The path provided with ``SOURCE_SUBDIR`` must be relative
+      and will be treated as relative to the top directory.  It can also
+      point to a directory that does not contain a ``CMakeLists.txt`` file
+      or even to a directory that doesn't exist.  This can be used to avoid
+      adding a project that contains a ``CMakeLists.txt`` file in its top
+      directory.
+
+  Projects should aim to declare the details of all dependencies they might
+  use before they call ``FetchContent_MakeAvailable()`` for any of them.
+  This ensures that if any of the dependencies are also sub-dependencies of
+  one or more of the others, the main project still controls the details
+  that will be used (because it will declare them first before the
+  dependencies get a chance to).  In the following code samples, assume that
+  the ``uses_other`` dependency also uses ``FetchContent`` to add the ``other``
+  dependency internally:
 
-    # Bring the populated content into the build
-    add_subdirectory(${${lcName}_SOURCE_DIR} ${${lcName}_BINARY_DIR})
-  endif()
+  .. code-block:: cmake
+
+    # WRONG: Should declare all details first
+    FetchContent_Declare(uses_other ...)
+    FetchContent_MakeAvailable(uses_other)
 
-The above is such a common pattern that, where no custom steps are needed
-between the calls to :command:`FetchContent_Populate` and
-:command:`add_subdirectory`, equivalent logic can be obtained by calling
-:command:`FetchContent_MakeAvailable` instead.  Where it meets the needs of
-the project, :command:`FetchContent_MakeAvailable` should be preferred, as it
-is simpler and provides additional features over the pattern above.
+    FetchContent_Declare(other ...)    # Will be ignored, uses_other beat us to it
+    FetchContent_MakeAvailable(other)  # Would use details declared by uses_other
+
+  .. code-block:: cmake
+
+    # CORRECT: All details declared first, so they will take priority
+    FetchContent_Declare(uses_other ...)
+    FetchContent_Declare(other ...)
+    FetchContent_MakeAvailable(uses_other other)
 
 .. command:: FetchContent_Populate
 
+  .. note::
+    Where possible, prefer to use :command:`FetchContent_MakeAvailable`
+    instead of implementing population manually with this command.
+
   .. code-block:: cmake
 
-    FetchContent_Populate( <name> )
+    FetchContent_Populate(<name>)
 
   In most cases, the only argument given to ``FetchContent_Populate()`` is the
   ``<name>``.  When used this way, the command assumes the content details have
@@ -211,88 +270,29 @@ is simpler and provides additional features over the pattern above.
   ``FetchContent_Populate()``.
 
   ``FetchContent_Populate()`` will set three variables in the scope of the
-  caller; ``<lcName>_POPULATED``, ``<lcName>_SOURCE_DIR`` and
-  ``<lcName>_BINARY_DIR``, where ``<lcName>`` is the lowercased ``<name>``.
-  ``<lcName>_POPULATED`` will always be set to ``True`` by the call.
-  ``<lcName>_SOURCE_DIR`` is the location where the
-  content can be found upon return (it will have already been populated), while
-  ``<lcName>_BINARY_DIR`` is a directory intended for use as a corresponding
-  build directory.  The main use case for the two directory variables is to
-  call :command:`add_subdirectory` immediately after population, i.e.:
+  caller:
+
+  ``<lowercaseName>_POPULATED``
+    This will always be set to ``TRUE`` by the call.
+
+  ``<lowercaseName>_SOURCE_DIR``
+    The location where the populated content can be found upon return.
+
+  ``<lowercaseName>_BINARY_DIR``
+    A directory intended for use as a corresponding build directory.
+
+  The main use case for the ``<lowercaseName>_SOURCE_DIR`` and
+  ``<lowercaseName>_BINARY_DIR`` variables is to call
+  :command:`add_subdirectory` immediately after population:
 
   .. code-block:: cmake
 
-    FetchContent_Populate(FooBar ...)
+    FetchContent_Populate(FooBar)
     add_subdirectory(${foobar_SOURCE_DIR} ${foobar_BINARY_DIR})
 
   The values of the three variables can also be retrieved from anywhere in the
   project hierarchy using the :command:`FetchContent_GetProperties` command.
 
-  A number of cache variables influence the behavior of all content population
-  performed using details saved from a :command:`FetchContent_Declare` call:
-
-  ``FETCHCONTENT_BASE_DIR``
-    In most cases, the saved details do not specify any options relating to the
-    directories to use for the internal sub-build, final source and build areas.
-    It is generally best to leave these decisions up to the ``FetchContent``
-    module to handle on the project's behalf.  The ``FETCHCONTENT_BASE_DIR``
-    cache variable controls the point under which all content population
-    directories are collected, but in most cases developers would not need to
-    change this.  The default location is ``${CMAKE_BINARY_DIR}/_deps``, but if
-    developers change this value, they should aim to keep the path short and
-    just below the top level of the build tree to avoid running into path
-    length problems on Windows.
-
-  ``FETCHCONTENT_QUIET``
-    The logging output during population can be quite verbose, making the
-    configure stage quite noisy.  This cache option (``ON`` by default) hides
-    all population output unless an error is encountered.  If experiencing
-    problems with hung downloads, temporarily switching this option off may
-    help diagnose which content population is causing the issue.
-
-  ``FETCHCONTENT_FULLY_DISCONNECTED``
-    When this option is enabled, no attempt is made to download or update
-    any content.  It is assumed that all content has already been populated in
-    a previous run or the source directories have been pointed at existing
-    contents the developer has provided manually (using options described
-    further below).  When the developer knows that no changes have been made to
-    any content details, turning this option ``ON`` can significantly speed up
-    the configure stage.  It is ``OFF`` by default.
-
-  ``FETCHCONTENT_UPDATES_DISCONNECTED``
-    This is a less severe download/update control compared to
-    ``FETCHCONTENT_FULLY_DISCONNECTED``.  Instead of bypassing all download and
-    update logic, the ``FETCHCONTENT_UPDATES_DISCONNECTED`` only disables the
-    update stage.  Therefore, if content has not been downloaded previously,
-    it will still be downloaded when this option is enabled.  This can speed up
-    the configure stage, but not as much as
-    ``FETCHCONTENT_FULLY_DISCONNECTED``.  It is ``OFF`` by default.
-
-  In addition to the above cache variables, the following cache variables are
-  also defined for each content name (``<ucName>`` is the uppercased value of
-  ``<name>``):
-
-  ``FETCHCONTENT_SOURCE_DIR_<ucName>``
-    If this is set, no download or update steps are performed for the specified
-    content and the ``<lcName>_SOURCE_DIR`` variable returned to the caller is
-    pointed at this location.  This gives developers a way to have a separate
-    checkout of the content that they can modify freely without interference
-    from the build.  The build simply uses that existing source, but it still
-    defines ``<lcName>_BINARY_DIR`` to point inside its own build area.
-    Developers are strongly encouraged to use this mechanism rather than
-    editing the sources populated in the default location, as changes to
-    sources in the default location can be lost when content population details
-    are changed by the project.
-
-  ``FETCHCONTENT_UPDATES_DISCONNECTED_<ucName>``
-    This is the per-content equivalent of
-    ``FETCHCONTENT_UPDATES_DISCONNECTED``. If the global option or this option
-    is ``ON``, then updates will be disabled for the named content.
-    Disabling updates for individual content can be useful for content whose
-    details rarely change, while still leaving other frequently changing
-    content with updates enabled.
-
-
   The ``FetchContent_Populate()`` command also supports a syntax allowing the
   content details to be specified directly rather than using any saved
   details.  This is more low-level and use of this form is generally to be
@@ -303,7 +303,8 @@ is simpler and provides additional features over the pattern above.
 
   .. code-block:: cmake
 
-    FetchContent_Populate( <name>
+    FetchContent_Populate(
+      <name>
       [QUIET]
       [SUBBUILD_DIR <subBuildDir>]
       [SOURCE_DIR <srcDir>]
@@ -325,16 +326,17 @@ is simpler and provides additional features over the pattern above.
   - The ``FETCHCONTENT_FULLY_DISCONNECTED`` and
     ``FETCHCONTENT_UPDATES_DISCONNECTED`` cache variables are ignored.
 
-  The ``<lcName>_SOURCE_DIR`` and ``<lcName>_BINARY_DIR`` variables are still
-  returned to the caller, but since these locations are not stored as global
-  properties when this form is used, they are only available to the calling
-  scope and below rather than the entire project hierarchy.  No
-  ``<lcName>_POPULATED`` variable is set in the caller's scope with this form.
+  The ``<lowercaseName>_SOURCE_DIR`` and ``<lowercaseName>_BINARY_DIR``
+  variables are still returned to the caller, but since these locations are
+  not stored as global properties when this form is used, they are only
+  available to the calling scope and below rather than the entire project
+  hierarchy.  No ``<lowercaseName>_POPULATED`` variable is set in the caller's
+  scope with this form.
 
   The supported options for ``FetchContent_Populate()`` are the same as those
   for :command:`FetchContent_Declare()`.  Those few options shown just
   above are either specific to ``FetchContent_Populate()`` or their behavior is
-  slightly modified from how :command:`ExternalProject_Add` treats them.
+  slightly modified from how :command:`ExternalProject_Add` treats them:
 
   ``QUIET``
     The ``QUIET`` option can be given to hide the output associated with
@@ -347,9 +349,9 @@ is simpler and provides additional features over the pattern above.
   ``SUBBUILD_DIR``
     The ``SUBBUILD_DIR`` argument can be provided to change the location of the
     sub-build created to perform the population.  The default value is
-    ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-subbuild`` and it would be unusual
-    to need to override this default.  If a relative path is specified, it will
-    be interpreted as relative to :variable:`CMAKE_CURRENT_BINARY_DIR`.
+    ``${CMAKE_CURRENT_BINARY_DIR}/<lowercaseName>-subbuild`` and it would be
+    unusual to need to override this default.  If a relative path is specified,
+    it will be interpreted as relative to :variable:`CMAKE_CURRENT_BINARY_DIR`.
     This option should not be confused with the ``SOURCE_SUBDIR`` option which
     only affects the :command:`FetchContent_MakeAvailable` command.
 
@@ -357,9 +359,9 @@ is simpler and provides additional features over the pattern above.
     The ``SOURCE_DIR`` and ``BINARY_DIR`` arguments are supported by
     :command:`ExternalProject_Add`, but different default values are used by
     ``FetchContent_Populate()``.  ``SOURCE_DIR`` defaults to
-    ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-src`` and ``BINARY_DIR`` defaults to
-    ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-build``.  If a relative path is
-    specified, it will be interpreted as relative to
+    ``${CMAKE_CURRENT_BINARY_DIR}/<lowercaseName>-src`` and ``BINARY_DIR``
+    defaults to ``${CMAKE_CURRENT_BINARY_DIR}/<lowercaseName>-build``.
+    If a relative path is specified, it will be interpreted as relative to
     :variable:`CMAKE_CURRENT_BINARY_DIR`.
 
   In addition to the above explicit options, any other unrecognized options are
@@ -380,11 +382,12 @@ is simpler and provides additional features over the pattern above.
   on the command line invoking the script.
 
   .. versionadded:: 3.18
-    Added support for ``DOWNLOAD_NO_EXTRACT`` and ``SOURCE_SUBDIR`` options.
+    Added support for the ``DOWNLOAD_NO_EXTRACT`` option.
 
 .. command:: FetchContent_GetProperties
 
-  When using saved content details, a call to :command:`FetchContent_Populate`
+  When using saved content details, a call to
+  :command:`FetchContent_MakeAvailable` or :command:`FetchContent_Populate`
   records information in global properties which can be queried at any time.
   This information includes the source and binary directories associated with
   the content and also whether or not the content population has been processed
@@ -392,7 +395,8 @@ is simpler and provides additional features over the pattern above.
 
   .. code-block:: cmake
 
-    FetchContent_GetProperties( <name>
+    FetchContent_GetProperties(
+      <name>
       [SOURCE_DIR <srcDirVar>]
       [BINARY_DIR <binDirVar>]
       [POPULATED <doneVar>]
@@ -403,49 +407,104 @@ is simpler and provides additional features over the pattern above.
   which is the name of the variable in which to store that property.  Most of
   the time though, only ``<name>`` is given, in which case the call will then
   set the same variables as a call to
-  :command:`FetchContent_Populate(name) <FetchContent_Populate>`.  This allows
-  the following canonical pattern to be used, which ensures that the relevant
-  variables will always be defined regardless of whether or not the population
-  has been performed elsewhere in the project already:
+  :command:`FetchContent_MakeAvailable(name) <FetchContent_MakeAvailable>` or
+  :command:`FetchContent_Populate(name) <FetchContent_Populate>`.
 
-  .. code-block:: cmake
-
-    FetchContent_GetProperties(foobar)
-    if(NOT foobar_POPULATED)
-      FetchContent_Populate(foobar)
-      ...
-    endif()
-
-  The above pattern allows other parts of the overall project hierarchy to
-  re-use the same content and ensure that it is only populated once.
-
-
-.. command:: FetchContent_MakeAvailable
+  This command is rarely needed when using
+  :command:`FetchContent_MakeAvailable`.  It is more commonly used as part of
+  implementing the following pattern with :command:`FetchContent_Populate`,
+  which ensures that the relevant variables will always be defined regardless
+  of whether or not the population has been performed elsewhere in the project
+  already:
 
   .. code-block:: cmake
 
-    FetchContent_MakeAvailable( <name1> [<name2>...] )
+    # Check if population has already been performed
+    FetchContent_GetProperties(depname)
+    if(NOT depname_POPULATED)
+      # Fetch the content using previously declared details
+      FetchContent_Populate(depname)
 
-  .. versionadded:: 3.14
+      # Set custom variables, policies, etc.
+      # ...
 
-  This command implements the common pattern typically needed for most
-  dependencies.  It iterates over each of the named dependencies in turn
-  and for each one it loosely follows the
-  :ref:`canonical pattern <fetch-content-canonical-pattern>` as
-  presented at the beginning of this section.  An important difference is
-  that :command:`add_subdirectory` will only be called on the
-  populated content if there is a ``CMakeLists.txt`` file in its top level
-  source directory.  This allows the command to be used for dependencies
-  that make downloaded content available at a known location but which do
-  not need or support being added directly to the build.
-
-  The ``SOURCE_SUBDIR`` option can be given in the declared details to
-  instruct ``FetchContent_MakeAvailable()`` to look for a ``CMakeLists.txt``
-  file in a subdirectory below the top level (i.e. the same way that
-  ``SOURCE_SUBDIR`` is used by the :command:`ExternalProject_Add` command).
-  ``SOURCE_SUBDIR`` must always be a relative path.  See the next section
-  for an example of this option.
+      # Bring the populated content into the build
+      add_subdirectory(${depname_SOURCE_DIR} ${depname_BINARY_DIR})
+    endif()
 
+Variables
+^^^^^^^^^
+
+A number of cache variables can influence the behavior where details from a
+:command:`FetchContent_Declare` call are used to populate content.
+The variables are all intended for the developer to customize behavior and
+should not normally be set by the project.
+
+.. variable:: FETCHCONTENT_BASE_DIR
+
+  In most cases, the saved details do not specify any options relating to the
+  directories to use for the internal sub-build, final source and build areas.
+  It is generally best to leave these decisions up to the ``FetchContent``
+  module to handle on the project's behalf.  The ``FETCHCONTENT_BASE_DIR``
+  cache variable controls the point under which all content population
+  directories are collected, but in most cases, developers would not need to
+  change this.  The default location is ``${CMAKE_BINARY_DIR}/_deps``, but if
+  developers change this value, they should aim to keep the path short and
+  just below the top level of the build tree to avoid running into path
+  length problems on Windows.
+
+.. variable:: FETCHCONTENT_QUIET
+
+  The logging output during population can be quite verbose, making the
+  configure stage quite noisy.  This cache option (``ON`` by default) hides
+  all population output unless an error is encountered.  If experiencing
+  problems with hung downloads, temporarily switching this option off may
+  help diagnose which content population is causing the issue.
+
+.. variable:: FETCHCONTENT_FULLY_DISCONNECTED
+
+  When this option is enabled, no attempt is made to download or update
+  any content.  It is assumed that all content has already been populated in
+  a previous run or the source directories have been pointed at existing
+  contents the developer has provided manually (using options described
+  further below).  When the developer knows that no changes have been made to
+  any content details, turning this option ``ON`` can significantly speed up
+  the configure stage.  It is ``OFF`` by default.
+
+.. variable:: FETCHCONTENT_UPDATES_DISCONNECTED
+
+  This is a less severe download/update control compared to
+  :variable:`FETCHCONTENT_FULLY_DISCONNECTED`.  Instead of bypassing all
+  download and update logic, ``FETCHCONTENT_UPDATES_DISCONNECTED`` only
+  disables the update stage.  Therefore, if content has not been downloaded
+  previously, it will still be downloaded when this option is enabled.
+  This can speed up the configure stage, but not as much as
+  :variable:`FETCHCONTENT_FULLY_DISCONNECTED`.  It is ``OFF`` by default.
+
+In addition to the above cache variables, the following cache variables are
+also defined for each content name:
+
+.. variable:: FETCHCONTENT_SOURCE_DIR_<uppercaseName>
+
+  If this is set, no download or update steps are performed for the specified
+  content and the ``<lowercaseName>_SOURCE_DIR`` variable returned to the
+  caller is pointed at this location.  This gives developers a way to have a
+  separate checkout of the content that they can modify freely without
+  interference from the build.  The build simply uses that existing source,
+  but it still defines ``<lowercaseName>_BINARY_DIR`` to point inside its own
+  build area.  Developers are strongly encouraged to use this mechanism rather
+  than editing the sources populated in the default location, as changes to
+  sources in the default location can be lost when content population details
+  are changed by the project.
+
+.. variable:: FETCHCONTENT_UPDATES_DISCONNECTED_<uppercaseName>
+
+  This is the per-content equivalent of
+  :variable:`FETCHCONTENT_UPDATES_DISCONNECTED`.  If the global option or
+  this option is ``ON``, then updates will be disabled for the named content.
+  Disabling updates for individual content can be useful for content whose
+  details rarely change, while still leaving other frequently changing content
+  with updates enabled.
 
 .. _`fetch-content-examples`:
 
@@ -470,7 +529,7 @@ frameworks are available to the main build:
   )
 
   # After the following call, the CMake targets defined by googletest and
-  # Catch2 will be defined and available to the rest of the build
+  # Catch2 will be available to the rest of the build
   FetchContent_MakeAvailable(googletest Catch2)
 
 If the sub-project's ``CMakeLists.txt`` file is not at the top level of its
@@ -964,18 +1023,29 @@ ExternalProject_Add_Step(${contentName}-populate copyfile
     unset(subCMakeOpts)
   endif()
 
-  if(DEFINED CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY)
-    list(APPEND subCMakeOpts
-      "-DCMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY=${CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY}")
-  endif()
+  set(__FETCHCONTENT_CACHED_INFO "")
+  set(__passthrough_vars
+    CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY
+    CMAKE_TLS_VERIFY
+    CMAKE_TLS_CAINFO
+    CMAKE_NETRC
+    CMAKE_NETRC_FILE
+  )
+  foreach(var IN LISTS __passthrough_vars)
+    if(DEFINED ${var})
+      # Embed directly in the generated CMakeLists.txt file to avoid making
+      # the cmake command line excessively long. It also makes debugging and
+      # testing easier.
+      string(APPEND __FETCHCONTENT_CACHED_INFO "set(${var} [==[${${var}}]==])\n")
+    endif()
+  endforeach()
 
   # Avoid using if(... IN_LIST ...) so we don't have to alter policy settings
-  set(__FETCHCONTENT_CACHED_INFO "")
   list(FIND ARG_UNPARSED_ARGUMENTS GIT_REPOSITORY indexResult)
   if(indexResult GREATER_EQUAL 0)
     find_package(Git QUIET)
-    set(__FETCHCONTENT_CACHED_INFO
-"# Pass through things we've already detected in the main project to avoid
+    string(APPEND __FETCHCONTENT_CACHED_INFO "
+# Pass through things we've already detected in the main project to avoid
 # paying the cost of redetecting them again in ExternalProject_Add()
 set(GIT_EXECUTABLE [==[${GIT_EXECUTABLE}]==])
 set(GIT_VERSION_STRING [==[${GIT_VERSION_STRING}]==])
index 726ff75..308138f 100644 (file)
@@ -35,6 +35,19 @@ The following variables may be set to influence this module's behavior:
   if set ``pkg-config`` will be used to search for a BLAS library first
   and if one is found that is preferred
 
+``BLA_SIZEOF_INTEGER``
+  .. versionadded:: 3.22
+
+  Specify the BLAS/LAPACK library integer size:
+
+  ``4``
+    Search for a BLAS/LAPACK with 32-bit integer interfaces.
+  ``8``
+    Search for a BLAS/LAPACK with 64-bit integer interfaces.
+  ``ANY``
+    Search for any BLAS/LAPACK.
+    Most likely, a BLAS/LAPACK with 32-bit integer interfaces will be found.
+
 Imported targets
 ^^^^^^^^^^^^^^^^
 
@@ -101,15 +114,16 @@ BLAS/LAPACK Vendors
 ``FlexiBLAS``
   .. versionadded:: 3.19
 
-``Fujitsu_SSL2``, ``Fujitsu_SSL2BLAMP``
+``Fujitsu_SSL2``, ``Fujitsu_SSL2BLAMP``, ``Fujitsu_SSL2SVE``, ``Fujitsu_SSL2BLAMPSVE``
   .. versionadded:: 3.20
 
-  Fujitsu SSL2 serial and parallel blas/lapack
+  Fujitsu SSL2 serial and parallel blas/lapack with SVE instructions
 
 ``Goto``
   GotoBLAS
 
-``IBMESSL``
+``IBMESSL``, ``IBMESSL_SMP``
+
   IBM Engineering and Scientific Subroutine Library
 
 ``Intel``
@@ -150,7 +164,7 @@ BLAS/LAPACK Vendors
 ``PhiPACK``
   Portable High Performance ANSI C (PHiPAC)
 
-``SCSL``
+``SCSL``, ``SCSL_mp``
   Scientific Computing Software Library
 
 ``SGIMATH``
@@ -312,9 +326,9 @@ function(CHECK_BLAS_LIBRARIES LIBRARIES _prefix _name _flags _list _deps _addlib
       list(APPEND _libraries "${_library}")
     else()
       string(REGEX REPLACE "[^A-Za-z0-9]" "_" _lib_var "${_library}")
-      set(_combined_name ${_combined_name}_${_lib_var})
+      string(APPEND _combined_name "_${_lib_var}")
       if(NOT "${_deps}" STREQUAL "")
-        set(_combined_name ${_combined_name}_deps)
+        string(APPEND _combined_name "_deps")
       endif()
       if(_libraries_work)
         find_library(${_prefix}_${_lib_var}_LIBRARY
@@ -332,7 +346,7 @@ function(CHECK_BLAS_LIBRARIES LIBRARIES _prefix _name _flags _list _deps _addlib
 
   foreach(_flag ${_flags})
     string(REGEX REPLACE "[^A-Za-z0-9]" "_" _flag_var "${_flag}")
-    set(_combined_name ${_combined_name}_${_flag_var})
+    string(APPEND _combined_name "_${_flag_var}")
   endforeach()
   if(_libraries_work)
     # Test this combination of libraries.
@@ -371,6 +385,17 @@ else()
   endif()
 endif()
 
+if(NOT BLA_SIZEOF_INTEGER)
+  # in the reality we do not know which API of BLAS/LAPACK is masked in library
+  set(_blas_sizeof_integer "ANY")
+elseif((BLA_SIZEOF_INTEGER STREQUAL "ANY") OR
+       (BLA_SIZEOF_INTEGER STREQUAL "4") OR
+       (BLA_SIZEOF_INTEGER STREQUAL "8"))
+  set(_blas_sizeof_integer ${BLA_SIZEOF_INTEGER})
+else()
+  message(FATAL_ERROR "BLA_SIZEOF_INTEGER can have only <no value>, ANY, 4, or 8 values")
+endif()
+
 # Implicitly linked BLAS libraries?
 if(BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
@@ -386,6 +411,8 @@ if(BLA_VENDOR STREQUAL "All")
       )
   endif()
   if(BLAS_WORKS)
+    # Give a more helpful "found" message
+    set(BLAS_WORKS "implicitly linked")
     set(_blas_fphsa_req_var BLAS_WORKS)
   endif()
 endif()
@@ -429,17 +456,23 @@ if(BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
         find_package(Threads REQUIRED)
       endif()
 
-      if(BLA_VENDOR MATCHES "_64ilp")
+      if(_blas_sizeof_integer EQUAL 8)
         set(BLAS_mkl_ILP_MODE "ilp64")
-      else()
+      elseif(_blas_sizeof_integer EQUAL 4)
         set(BLAS_mkl_ILP_MODE "lp64")
+      else()
+        if(BLA_VENDOR MATCHES "_64ilp")
+          set(BLAS_mkl_ILP_MODE "ilp64")
+        else()
+          set(BLAS_mkl_ILP_MODE "lp64")
+        endif()
       endif()
 
       set(BLAS_SEARCH_LIBS "")
 
       if(BLA_F95)
         set(BLAS_mkl_SEARCH_SYMBOL "sgemm_f95")
-        set(_LIBRARIES BLAS95_LIBRARIES)
+        set(_BLAS_LIBRARIES BLAS95_LIBRARIES)
         if(WIN32)
           # Find the main file (32-bit or 64-bit)
           set(BLAS_SEARCH_LIBS_WIN_MAIN "")
@@ -501,7 +534,7 @@ if(BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
         endif()
       else()
         set(BLAS_mkl_SEARCH_SYMBOL sgemm)
-        set(_LIBRARIES BLAS_LIBRARIES)
+        set(_BLAS_LIBRARIES BLAS_LIBRARIES)
         if(WIN32)
           # Find the main file (32-bit or 64-bit)
           set(BLAS_SEARCH_LIBS_WIN_MAIN "")
@@ -613,15 +646,15 @@ if(BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
           "lib/${BLAS_mkl_ARCH_NAME}"
           )
 
-      foreach(IT ${BLAS_SEARCH_LIBS})
-        string(REPLACE " " ";" SEARCH_LIBS ${IT})
-        if(NOT ${_LIBRARIES})
+      foreach(_search ${BLAS_SEARCH_LIBS})
+        string(REPLACE " " ";" _search ${_search})
+        if(NOT ${_BLAS_LIBRARIES})
           check_blas_libraries(
-            ${_LIBRARIES}
+            ${_BLAS_LIBRARIES}
             BLAS
             ${BLAS_mkl_SEARCH_SYMBOL}
             ""
-            "${SEARCH_LIBS}"
+            "${_search}"
             "${CMAKE_THREAD_LIBS_INIT};${BLAS_mkl_LM};${BLAS_mkl_LDL}"
             "${BLAS_mkl_MKLROOT}"
             "${BLAS_mkl_LIB_PATH_SUFFIXES}"
@@ -629,6 +662,7 @@ if(BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
         endif()
       endforeach()
 
+      unset(_search)
       unset(BLAS_mkl_ILP_MODE)
       unset(BLAS_mkl_INTFACE)
       unset(BLAS_mkl_THREADING)
@@ -671,29 +705,43 @@ endif()
 
 # FlexiBLAS? (http://www.mpi-magdeburg.mpg.de/mpcsc/software/FlexiBLAS/)
 if(BLA_VENDOR STREQUAL "FlexiBLAS" OR BLA_VENDOR STREQUAL "All")
+  set(_blas_flexiblas_lib "flexiblas")
+
+  if(_blas_sizeof_integer EQUAL 8)
+    string(APPEND _blas_flexiblas_lib "64")
+  endif()
+
   if(NOT BLAS_LIBRARIES)
     check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
       ""
-      "flexiblas"
+      "${_blas_flexiblas_lib}"
       ""
       ""
       ""
       )
   endif()
+
+  unset(_blas_flexiblas_lib)
 endif()
 
 # OpenBLAS? (http://www.openblas.net)
 if(BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All")
+  set(_blas_openblas_lib "openblas")
+
+  if(_blas_sizeof_integer EQUAL 8)
+    string(APPEND _blas_openblas_lib "64")
+  endif()
+
   if(NOT BLAS_LIBRARIES)
     check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
       ""
-      "openblas"
+      "${_blas_openblas_lib}"
       ""
       ""
       ""
@@ -720,59 +768,75 @@ if(BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All")
       BLAS
       sgemm
       ""
-      "openblas"
+      "${_blas_openblas_lib}"
       "${_threadlibs}"
       ""
       ""
       )
     unset(_threadlibs)
   endif()
+
+  unset(_blas_openblas_lib)
 endif()
 
 # ArmPL blas library? (https://developer.arm.com/tools-and-software/server-and-hpc/compile/arm-compiler-for-linux/arm-performance-libraries)
 if(BLA_VENDOR MATCHES "Arm" OR BLA_VENDOR STREQUAL "All")
 
    # Check for 64bit Integer support
-   if(BLA_VENDOR MATCHES "_ilp64")
-     set(BLAS_armpl_LIB "armpl_ilp64")
-   else()
-     set(BLAS_armpl_LIB "armpl_lp64")
-   endif()
+  if(_blas_sizeof_integer EQUAL 8)
+    set(_blas_armpl_lib "armpl_ilp64")
+  elseif(_blas_sizeof_integer EQUAL 4)
+    set(_blas_armpl_lib "armpl_lp64")
+  else()
+    if(BLA_VENDOR MATCHES "_ilp64")
+      set(_blas_armpl_lib "armpl_ilp64")
+    else()
+      set(_blas_armpl_lib "armpl_lp64")
+    endif()
+  endif()
 
    # Check for OpenMP support, VIA BLA_VENDOR of Arm_mp or Arm_ipl64_mp
    if(BLA_VENDOR MATCHES "_mp")
-     set(BLAS_armpl_LIB "${BLAS_armpl_LIB}_mp")
+     string(APPEND _blas_armpl_lib "_mp")
    endif()
 
    if(NOT BLAS_LIBRARIES)
-    check_blas_libraries(
-      BLAS_LIBRARIES
-      BLAS
-      sgemm
-      ""
-      "${BLAS_armpl_LIB}"
-      ""
-      ""
-      ""
-      )
+     check_blas_libraries(
+       BLAS_LIBRARIES
+       BLAS
+       sgemm
+       ""
+       "${_blas_armpl_lib}"
+       ""
+       ""
+       ""
+       )
   endif()
-
+  unset(_blas_armpl_lib)
 endif()
 
 # FLAME's blis library? (https://github.com/flame/blis)
 if(BLA_VENDOR STREQUAL "FLAME" OR BLA_VENDOR STREQUAL "All")
+  set(_blas_flame_lib "blis")
+
+  if(_blas_sizeof_integer EQUAL 8)
+    string(APPEND _blas_flame_lib "64")
+  endif()
+
   if(NOT BLAS_LIBRARIES)
     check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
       ""
-      "blis"
+      "${_blas_flame_lib}"
       ""
       ""
       ""
       )
   endif()
+
+  unset(_blas_flame_lib)
 endif()
 
 # BLAS in the ATLAS library? (http://math-atlas.sourceforge.net/)
@@ -809,33 +873,45 @@ endif()
 
 # BLAS in Alpha CXML library?
 if(BLA_VENDOR STREQUAL "CXML" OR BLA_VENDOR STREQUAL "All")
-  if(NOT BLAS_LIBRARIES)
-    check_blas_libraries(
-      BLAS_LIBRARIES
-      BLAS
-      sgemm
-      ""
-      "cxml"
-      ""
-      ""
-      ""
-      )
+  if(_blas_sizeof_integer EQUAL 8)
+    if(BLA_VENDOR STREQUAL "CXML")
+      message(FATAL_ERROR "CXML does not support Int64 type")
+    endif()
+  else()
+    if(NOT BLAS_LIBRARIES)
+      check_blas_libraries(
+        BLAS_LIBRARIES
+        BLAS
+        sgemm
+        ""
+        "cxml"
+        ""
+        ""
+        ""
+        )
+    endif()
   endif()
 endif()
 
 # BLAS in Alpha DXML library? (now called CXML, see above)
 if(BLA_VENDOR STREQUAL "DXML" OR BLA_VENDOR STREQUAL "All")
-  if(NOT BLAS_LIBRARIES)
-    check_blas_libraries(
-      BLAS_LIBRARIES
-      BLAS
-      sgemm
-      ""
-      "dxml"
-      ""
-      ""
-      ""
-      )
+  if(_blas_sizeof_integer EQUAL 8)
+    if(BLA_VENDOR STREQUAL "DXML")
+      message(FATAL_ERROR "DXML does not support Int64 type")
+    endif()
+  else()
+    if(NOT BLAS_LIBRARIES)
+      check_blas_libraries(
+        BLAS_LIBRARIES
+        BLAS
+        sgemm
+        ""
+        "dxml"
+        ""
+        ""
+        ""
+        )
+    endif()
   endif()
 endif()
 
@@ -859,19 +935,30 @@ if(BLA_VENDOR STREQUAL "SunPerf" OR BLA_VENDOR STREQUAL "All")
 endif()
 
 # BLAS in SCSL library?  (SGI/Cray Scientific Library)
-if(BLA_VENDOR STREQUAL "SCSL" OR BLA_VENDOR STREQUAL "All")
+if(BLA_VENDOR MATCHES "SCSL" OR BLA_VENDOR STREQUAL "All")
+  set(_blas_scsl_lib "scs")
+
+  if(_blas_sizeof_integer EQUAL 8)
+    string(APPEND _blas_scsl_lib "_i8")
+  endif()
+  if(BLA_VENDOR MATCHES "_mp")
+    string(APPEND _blas_scsl_lib "_mp")
+  endif()
+
   if(NOT BLAS_LIBRARIES)
     check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
       ""
-      "scsl"
+      "${_blas_scsl_lib}"
       ""
       ""
       ""
       )
   endif()
+
+  unset(_blas_scsl_lib)
 endif()
 
 # BLAS in SGIMATH library?
@@ -890,20 +977,31 @@ if(BLA_VENDOR STREQUAL "SGIMATH" OR BLA_VENDOR STREQUAL "All")
   endif()
 endif()
 
-# BLAS in IBM ESSL library? (requires generic BLAS lib, too)
-if(BLA_VENDOR STREQUAL "IBMESSL" OR BLA_VENDOR STREQUAL "All")
+# BLAS in IBM ESSL library?
+if(BLA_VENDOR MATCHES "IBMESSL" OR BLA_VENDOR STREQUAL "All")
+  set(_blas_essl_lib "essl")
+
+  if(BLA_VENDOR MATCHES "_SMP")
+    string(APPEND _blas_essl_lib "smp")
+  endif()
+  if(_blas_sizeof_integer EQUAL 8)
+    string(APPEND _blas_essl_lib "6464")
+  endif()
+
   if(NOT BLAS_LIBRARIES)
     check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
       ""
-      "essl;blas"
+      "${_blas_essl_lib}"
       ""
       ""
       ""
       )
   endif()
+
+  unset(_blas_essl_lib)
 endif()
 
 # BLAS in acml library?
@@ -927,7 +1025,7 @@ if(BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All")
   list(GET _ACML_GPU_ROOT 0 _ACML_GPU_ROOT)
   if(_ACML_ROOT)
     get_filename_component(_ACML_ROOT ${_ACML_ROOT} PATH)
-    if(SIZEOF_INTEGER EQUAL 8)
+    if(_blas_sizeof_integer EQUAL 8)
       set(_ACML_PATH_SUFFIX "_int64")
     else()
       set(_ACML_PATH_SUFFIX "")
@@ -1054,102 +1152,179 @@ endif() # ACML
 
 # Apple BLAS library?
 if(BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All")
+  if(_blas_sizeof_integer EQUAL 8)
+    if(BLA_VENDOR STREQUAL "Apple")
+      message(FATAL_ERROR "Accelerate Framework does not support Int64 type")
+    endif()
+  else()
+    if(NOT BLAS_LIBRARIES)
+      check_blas_libraries(
+        BLAS_LIBRARIES
+        BLAS
+        dgemm
+        ""
+        "Accelerate"
+        ""
+        ""
+        ""
+        )
+    endif()
+  endif()
+endif()
+
+# Apple NAS (vecLib) library?
+if(BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All")
+  if(_blas_sizeof_integer EQUAL 8)
+    if(BLA_VENDOR STREQUAL "NAS")
+      message(FATAL_ERROR "Accelerate Framework does not support Int64 type")
+    endif()
+  else()
+    if(NOT BLAS_LIBRARIES)
+      check_blas_libraries(
+        BLAS_LIBRARIES
+        BLAS
+        dgemm
+        ""
+        "vecLib"
+        ""
+        ""
+        ""
+        )
+    endif()
+  endif()
+endif()
+
+# Elbrus Math Library?
+if(BLA_VENDOR MATCHES "EML" OR BLA_VENDOR STREQUAL "All")
+
+  set(_blas_eml_lib "eml")
+
+  if(_blas_sizeof_integer EQUAL 8)
+    string(APPEND _blas_eml_lib "_ilp64")
+  endif()
+  # Check for OpenMP support, VIA BLA_VENDOR of eml_mt
+  if(BLA_VENDOR MATCHES "_mt")
+    string(APPEND _blas_eml_lib "_mt")
+  endif()
+
   if(NOT BLAS_LIBRARIES)
     check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
-      dgemm
+      sgemm
       ""
-      "Accelerate"
+      "${_blas_eml_lib}"
       ""
       ""
       ""
       )
   endif()
+  unset(_blas_eml_lib)
 endif()
 
-# Apple NAS (vecLib) library?
-if(BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All")
+# Fujitsu SSL2 Library?
+if(NOT BLAS_LIBRARIES
+    AND (BLA_VENDOR MATCHES "^Fujitsu_SSL2" OR BLA_VENDOR STREQUAL "All"))
+  set(_blas_fjlapack_lib "fjlapack")
+  set(_blas_fjlapack_flags "-Kopenmp")
+
+  if(BLA_VENDOR MATCHES "BLAMP")
+    string(APPEND _blas_fjlapack_lib "ex")
+  endif()
+  if(BLA_VENDOR MATCHES "SVE")
+    string(APPEND _blas_fjlapack_lib "sve")
+  endif()
+  if(_blas_sizeof_integer EQUAL 8)
+    string(APPEND _blas_fjlapack_lib "_ilp64")
+  endif()
+
   if(NOT BLAS_LIBRARIES)
     check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
-      dgemm
-      ""
-      "vecLib"
+      sgemm
+      "${_blas_fjlapack_flags}"
+      "${_blas_fjlapack_lib}"
       ""
       ""
       ""
       )
+    if(BLAS_LIBRARIES)
+      set(BLAS_LINKER_FLAGS ${_blas_fjlapack_flags})
+    endif()
   endif()
-endif()
 
-# Elbrus Math Library?
-if(BLA_VENDOR MATCHES "EML" OR BLA_VENDOR STREQUAL "All")
+  unset(_blas_fjlapack_flags)
+  unset(_blas_fjlapack_lib)
+endif()
 
-   set(BLAS_EML_LIB "eml")
+# BLAS in nVidia HPC SDK? (https://developer.nvidia.com/hpc-sdk)
+if(BLA_VENDOR STREQUAL "NVHPC" OR BLA_VENDOR STREQUAL "All")
+  set(_blas_nvhpc_lib "blas")
 
-   # Check for OpenMP support, VIA BLA_VENDOR of eml_mt
-   if(BLA_VENDOR MATCHES "_mt")
-     set(BLAS_EML_LIB "${BLAS_EML_LIB}_mt")
-   endif()
+  if(_blas_sizeof_integer EQUAL 8)
+    string(APPEND _blas_nvhpc_lib "_ilp64")
+  elseif(_blas_sizeof_integer EQUAL 4)
+    string(APPEND _blas_nvhpc_lib "_lp64")
+  endif()
 
-   if(NOT BLAS_LIBRARIES)
+  if(NOT BLAS_LIBRARIES)
     check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
       ""
-      "${BLAS_EML_LIB}"
+      "${_blas_nvhpc_lib}"
       ""
       ""
       ""
       )
   endif()
 
-endif()
+  # an additional check for NVHPC 2020
+  # which does not have differentiation
+  # between lp64 and ilp64 modes
+  if(NOT BLAS_LIBRARIES AND NOT _blas_sizeof_integer EQUAL 8)
+    set(_blas_nvhpc_lib "blas")
 
-# Fujitsu SSL2 Library?
-if(NOT BLAS_LIBRARIES
-    AND (BLA_VENDOR MATCHES "Fujitsu_SSL2" OR BLA_VENDOR STREQUAL "All"))
-  if(BLA_VENDOR STREQUAL "Fujitsu_SSL2BLAMP")
-    set(_ssl2_suffix BLAMP)
-  else()
-    set(_ssl2_suffix)
-  endif()
-  check_blas_libraries(
-    BLAS_LIBRARIES
-    BLAS
-    sgemm
-    "-SSL2${_ssl2_suffix}"
-    ""
-    ""
-    ""
-    ""
-    )
-  if(BLAS_LIBRARIES)
-    set(BLAS_LINKER_FLAGS "-SSL2${_ssl2_suffix}")
-    set(_blas_fphsa_req_var BLAS_LINKER_FLAGS)
+    check_blas_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "${_blas_nvhpc_lib}"
+      ""
+      ""
+      ""
+      )
   endif()
-  unset(_ssl2_suffix)
+
+  unset(_blas_nvhpc_lib)
 endif()
 
 # Generic BLAS library?
 if(BLA_VENDOR STREQUAL "Generic" OR
-   BLA_VENDOR STREQUAL "NVHPC" OR
    BLA_VENDOR STREQUAL "All")
+  set(_blas_generic_lib "blas")
+
+  if(_blas_sizeof_integer EQUAL 8)
+    string(APPEND _blas_generic_lib "64")
+  endif()
+
   if(NOT BLAS_LIBRARIES)
     check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
       ""
-      "blas"
+      "${_blas_generic_lib}"
       ""
       ""
       ""
       )
   endif()
+
+  unset(_blas_generic_lib)
 endif()
 
 # On compilers that implicitly link BLAS (i.e. CrayPrgEnv) we used a
@@ -1163,3 +1338,6 @@ if(NOT BLA_F95)
 endif()
 
 _add_blas_target()
+unset(_blas_fphsa_req_var)
+unset(_blas_sizeof_integer)
+unset(_BLAS_LIBRARIES)
index 89b8c99..d22a676 100644 (file)
@@ -742,6 +742,19 @@ elseif(NOT CUDAToolkit_FIND_QUIETLY)
   message(STATUS "Unable to find cuda_runtime.h in \"${CUDAToolkit_TARGET_DIR}/include\" for CUDAToolkit_INCLUDE_DIR.")
 endif()
 
+# The NVHPC layout moves math library headers and libraries to a sibling directory.
+# Create a separate variable so this directory can be selectively added to math targets.
+if(NOT EXISTS "${CUDAToolkit_INCLUDE_DIR}/cublas_v2.h")
+  set(CUDAToolkit_MATH_INCLUDE_DIR "${CUDAToolkit_TARGET_DIR}/../../math_libs/include")
+  cmake_path(NORMAL_PATH CUDAToolkit_MATH_INCLUDE_DIR)
+  if(NOT EXISTS "${CUDAToolkit_MATH_INCLUDE_DIR}/cublas_v2.h")
+    if(NOT CUDAToolkit_FIND_QUIETLY)
+      message(STATUS "Unable to find cublas_v2.h in either \"${CUDAToolkit_INCLUDE_DIR}\" or \"${CUDAToolkit_MATH_INCLUDE_DIR}\"")
+    endif()
+    unset(CUDAToolkit_MATH_INCLUDE_DIR)
+  endif()
+endif()
+
 if(CUDAToolkit_NVCC_EXECUTABLE AND
    CMAKE_CUDA_COMPILER_VERSION AND
    CUDAToolkit_NVCC_EXECUTABLE STREQUAL CMAKE_CUDA_COMPILER)
@@ -844,14 +857,23 @@ if(CUDAToolkit_FOUND)
       HINTS ${CUDAToolkit_LIBRARY_DIR}
             ENV CUDA_PATH
       PATH_SUFFIXES lib64/stubs lib/x64/stubs lib/stubs stubs
+                    # Support NVHPC splayed math library layout
+                    ../../math_libs/${CUDAToolkit_VERSION_MAJOR}.${CUDAToolkit_VERSION_MINOR}/lib64
+                    ../../math_libs/lib64
     )
 
     mark_as_advanced(CUDA_${lib_name}_LIBRARY)
 
     if (NOT TARGET CUDA::${lib_name} AND CUDA_${lib_name}_LIBRARY)
-      add_library(CUDA::${lib_name} IMPORTED INTERFACE)
+      add_library(CUDA::${lib_name} UNKNOWN IMPORTED)
       target_include_directories(CUDA::${lib_name} SYSTEM INTERFACE "${CUDAToolkit_INCLUDE_DIRS}")
-      target_link_libraries(CUDA::${lib_name} INTERFACE "${CUDA_${lib_name}_LIBRARY}")
+      if(DEFINED CUDAToolkit_MATH_INCLUDE_DIR)
+        string(FIND ${CUDA_${lib_name}_LIBRARY} "math_libs" math_libs)
+        if(NOT ${math_libs} EQUAL -1)
+          target_include_directories(CUDA::${lib_name} SYSTEM INTERFACE "${CUDAToolkit_MATH_INCLUDE_DIR}")
+        endif()
+      endif()
+      set_property(TARGET CUDA::${lib_name} PROPERTY IMPORTED_LOCATION "${CUDA_${lib_name}_LIBRARY}")
       foreach(dep ${arg_DEPS})
         if(TARGET CUDA::${dep})
           target_link_libraries(CUDA::${lib_name} INTERFACE CUDA::${dep})
index bab7256..d54d2f6 100644 (file)
@@ -152,13 +152,17 @@ if(NOT FLTK_DIR)
 endif()
 
 # Check if FLTK was built using CMake
-if(EXISTS ${FLTK_DIR}/FLTKConfig.cmake)
-  set(FLTK_BUILT_WITH_CMAKE 1)
-endif()
+foreach(fltk_include IN LISTS FLTK_DIR)
+  if(EXISTS "${fltk_include}/FLTKConfig.cmake")
+    set(FLTK_BUILT_WITH_CMAKE 1)
+    set(FLTK_CMAKE_PATH "${fltk_include}/FLTKConfig.cmake")
+    break()
+  endif()
+endforeach()
 
 if(FLTK_BUILT_WITH_CMAKE)
   set(FLTK_FOUND 1)
-  include(${FLTK_DIR}/FLTKConfig.cmake)
+  include("${FLTK_CMAKE_PATH}")
 
   # Fluid
   if(FLUID_COMMAND)
index 2770c60..dd0975d 100644 (file)
@@ -41,8 +41,43 @@ Also defined, but not for general use are:
 #]=======================================================================]
 
 include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 
-if (WIN32)
+function(_add_glut_target_simple)
+  if(TARGET GLUT::GLUT)
+    return()
+  endif()
+  add_library(GLUT::GLUT INTERFACE IMPORTED)
+  if(GLUT_INCLUDE_DIRS)
+    target_include_directories(GLUT::GLUT SYSTEM
+      INTERFACE "${GLUT_INCLUDE_DIRS}")
+  endif()
+  if(GLUT_LIBRARIES)
+    target_link_libraries(GLUT::GLUT INTERFACE ${GLUT_LIBRARIES})
+  endif()
+  if(GLUT_LDFLAGS)
+    target_link_options(GLUT::GLUT INTERFACE ${GLUT_LDFLAGS})
+  endif()
+  if(GLUT_CFLAGS)
+    separate_arguments(GLUT_CFLAGS_SPLIT UNIX_COMMAND "${GLUT_CFLAGS}")
+    target_compile_options(GLUT::GLUT INTERFACE ${GLUT_CFLAGS_SPLIT})
+  endif()
+
+  set_property(TARGET GLUT::GLUT APPEND PROPERTY
+    IMPORTED_LOCATION "${GLUT_glut_LIBRARY}")
+endfunction()
+
+find_package(PkgConfig)
+if(PKG_CONFIG_FOUND)
+  pkg_check_modules(GLUT glut)
+  if(GLUT_FOUND)
+    _add_glut_target_simple()
+    FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLUT REQUIRED_VARS GLUT_FOUND)
+    return()
+  endif()
+endif()
+
+if(WIN32)
   find_path( GLUT_INCLUDE_DIR NAMES GL/glut.h
     PATHS  ${GLUT_ROOT_PATH}/include )
   find_library( GLUT_glut_LIBRARY_RELEASE NAMES glut glut32 freeglut
@@ -57,85 +92,75 @@ if (WIN32)
     )
   mark_as_advanced(GLUT_glut_LIBRARY_RELEASE GLUT_glut_LIBRARY_DEBUG)
   select_library_configurations(GLUT_glut)
-else ()
-
-  if (APPLE)
-    find_path(GLUT_INCLUDE_DIR glut.h ${OPENGL_LIBRARY_DIR})
-    find_library(GLUT_glut_LIBRARY GLUT DOC "GLUT library for OSX")
-    find_library(GLUT_cocoa_LIBRARY Cocoa DOC "Cocoa framework for OSX")
-    mark_as_advanced(GLUT_glut_LIBRARY GLUT_cocoa_LIBRARY)
-
-    if(GLUT_cocoa_LIBRARY AND NOT TARGET GLUT::Cocoa)
-      add_library(GLUT::Cocoa UNKNOWN IMPORTED)
-      # Cocoa should always be a Framework, but we check to make sure.
-      if(GLUT_cocoa_LIBRARY MATCHES "/([^/]+)\\.framework$")
-        set(_glut_cocoa "${GLUT_cocoa_LIBRARY}/${CMAKE_MATCH_1}")
-        if(EXISTS "${_glut_cocoa}.tbd")
-          string(APPEND _glut_cocoa ".tbd")
-        endif()
-        set_target_properties(GLUT::Cocoa PROPERTIES
-          IMPORTED_LOCATION "${_glut_cocoa}")
-      else()
-        set_target_properties(GLUT::Cocoa PROPERTIES
-          IMPORTED_LOCATION "${GLUT_cocoa_LIBRARY}")
+elseif(APPLE)
+  find_path(GLUT_INCLUDE_DIR glut.h ${OPENGL_LIBRARY_DIR})
+  find_library(GLUT_glut_LIBRARY GLUT DOC "GLUT library for OSX")
+  find_library(GLUT_cocoa_LIBRARY Cocoa DOC "Cocoa framework for OSX")
+  mark_as_advanced(GLUT_glut_LIBRARY GLUT_cocoa_LIBRARY)
+
+  if(GLUT_cocoa_LIBRARY AND NOT TARGET GLUT::Cocoa)
+    add_library(GLUT::Cocoa UNKNOWN IMPORTED)
+    # Cocoa should always be a Framework, but we check to make sure.
+    if(GLUT_cocoa_LIBRARY MATCHES "/([^/]+)\\.framework$")
+      set(_glut_cocoa "${GLUT_cocoa_LIBRARY}/${CMAKE_MATCH_1}")
+      if(EXISTS "${_glut_cocoa}.tbd")
+        string(APPEND _glut_cocoa ".tbd")
       endif()
-    endif()
-  else ()
-
-    if (BEOS)
-
-      set(_GLUT_INC_DIR /boot/develop/headers/os/opengl)
-      set(_GLUT_glut_LIB_DIR /boot/develop/lib/x86)
-
+      set_target_properties(GLUT::Cocoa PROPERTIES
+        IMPORTED_LOCATION "${_glut_cocoa}")
     else()
-
-      find_library( GLUT_Xi_LIBRARY Xi
-        /usr/openwin/lib
-        )
-      mark_as_advanced(GLUT_Xi_LIBRARY)
-
-      find_library( GLUT_Xmu_LIBRARY Xmu
-        /usr/openwin/lib
-        )
-      mark_as_advanced(GLUT_Xmu_LIBRARY)
-
-      if(GLUT_Xi_LIBRARY AND NOT TARGET GLUT::Xi)
-        add_library(GLUT::Xi UNKNOWN IMPORTED)
-        set_target_properties(GLUT::Xi PROPERTIES
-          IMPORTED_LOCATION "${GLUT_Xi_LIBRARY}")
-      endif()
-
-      if(GLUT_Xmu_LIBRARY AND NOT TARGET GLUT::Xmu)
-        add_library(GLUT::Xmu UNKNOWN IMPORTED)
-        set_target_properties(GLUT::Xmu PROPERTIES
-          IMPORTED_LOCATION "${GLUT_Xmu_LIBRARY}")
-      endif()
-
-    endif ()
-
-    find_path( GLUT_INCLUDE_DIR GL/glut.h
-      /usr/include/GL
-      /usr/openwin/share/include
-      /usr/openwin/include
-      /opt/graphics/OpenGL/include
-      /opt/graphics/OpenGL/contrib/libglut
-      ${_GLUT_INC_DIR}
+      set_target_properties(GLUT::Cocoa PROPERTIES
+        IMPORTED_LOCATION "${GLUT_cocoa_LIBRARY}")
+    endif()
+  endif()
+else()
+  if(BEOS)
+    set(_GLUT_INC_DIR /boot/develop/headers/os/opengl)
+    set(_GLUT_glut_LIB_DIR /boot/develop/lib/x86)
+  else()
+    find_library( GLUT_Xi_LIBRARY Xi
+      /usr/openwin/lib
       )
+    mark_as_advanced(GLUT_Xi_LIBRARY)
 
-    find_library( GLUT_glut_LIBRARY glut
+    find_library( GLUT_Xmu_LIBRARY Xmu
       /usr/openwin/lib
-      ${_GLUT_glut_LIB_DIR}
       )
-    mark_as_advanced(GLUT_glut_LIBRARY)
+    mark_as_advanced(GLUT_Xmu_LIBRARY)
 
-    unset(_GLUT_INC_DIR)
-    unset(_GLUT_glut_LIB_DIR)
+    if(GLUT_Xi_LIBRARY AND NOT TARGET GLUT::Xi)
+      add_library(GLUT::Xi UNKNOWN IMPORTED)
+      set_target_properties(GLUT::Xi PROPERTIES
+        IMPORTED_LOCATION "${GLUT_Xi_LIBRARY}")
+    endif()
+
+    if(GLUT_Xmu_LIBRARY AND NOT TARGET GLUT::Xmu)
+      add_library(GLUT::Xmu UNKNOWN IMPORTED)
+      set_target_properties(GLUT::Xmu PROPERTIES
+        IMPORTED_LOCATION "${GLUT_Xmu_LIBRARY}")
+    endif()
 
   endif ()
 
-endif ()
+  find_path( GLUT_INCLUDE_DIR GL/glut.h
+    /usr/include/GL
+    /usr/openwin/share/include
+    /usr/openwin/include
+    /opt/graphics/OpenGL/include
+    /opt/graphics/OpenGL/contrib/libglut
+    ${_GLUT_INC_DIR}
+    )
+
+  find_library( GLUT_glut_LIBRARY glut
+    /usr/openwin/lib
+    ${_GLUT_glut_LIB_DIR}
+    )
+
+  unset(_GLUT_INC_DIR)
+  unset(_GLUT_glut_LIB_DIR)
+endif()
+mark_as_advanced(GLUT_glut_LIBRARY)
 
-include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLUT REQUIRED_VARS GLUT_glut_LIBRARY GLUT_INCLUDE_DIR)
 
 if (GLUT_FOUND)
index e335355..6cadadb 100644 (file)
@@ -161,6 +161,8 @@ include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 # scope somewhere else. We can't rely on it because different components may
 # have been requested for this call.
 set(HDF5_FOUND OFF)
+set(HDF5_LIBRARIES)
+set(HDF5_HL_LIBRARIES)
 
 # List of the valid HDF5 components
 set(HDF5_VALID_LANGUAGE_BINDINGS C CXX Fortran)
@@ -560,7 +562,7 @@ if(NOT HDF5_FOUND AND NOT HDF5_NO_FIND_PACKAGE_CONFIG_FILE)
                 set(HDF5_${_lang}_FOUND TRUE)
             endif()
             if(HDF5_FIND_HL)
-                get_target_property(_lang_hl_location ${HDF5_${_lang}_HL_TARGET}${_suffix} IMPORTED_IMPLIB_${_hdf5_imported_conf} )
+                get_target_property(_hdf5_lang_hl_location ${HDF5_${_lang}_HL_TARGET}${_suffix} IMPORTED_IMPLIB_${_hdf5_imported_conf} )
                 if (NOT _hdf5_lang_hl_location)
                     get_target_property(_hdf5_lang_hl_location ${HDF5_${_lang}_HL_TARGET}${_suffix} LOCATION_${_hdf5_imported_conf})
                     if (NOT _hdf5_hl_lang_location)
@@ -586,6 +588,9 @@ if(NOT HDF5_FOUND)
   set(HDF5_COMPILER_NO_INTERROGATE TRUE)
   # Only search for languages we've enabled
   foreach(_lang IN LISTS HDF5_LANGUAGE_BINDINGS)
+    set(HDF5_${_lang}_LIBRARIES)
+    set(HDF5_${_lang}_HL_LIBRARIES)
+
     # First check to see if our regular compiler is one of wrappers
     if(_lang STREQUAL "C")
       _HDF5_test_regular_compiler_C(
@@ -811,6 +816,9 @@ if( NOT HDF5_FOUND )
     endif()
 
     foreach(_lang IN LISTS HDF5_LANGUAGE_BINDINGS)
+        set(HDF5_${_lang}_LIBRARIES)
+        set(HDF5_${_lang}_HL_LIBRARIES)
+
         # The "main" library.
         set(_hdf5_main_library "")
 
index 2bb49ad..1bae825 100644 (file)
@@ -172,7 +172,7 @@ function(_ICU_FIND)
       DOC "ICU ${program} executable"
       NO_PACKAGE_ROOT_PATH
       )
-    mark_as_advanced(cache_var)
+    mark_as_advanced("${cache_var}")
     set("${program_var}" "${${cache_var}}" PARENT_SCOPE)
   endforeach()
 
@@ -301,7 +301,7 @@ function(_ICU_FIND)
       HINTS ${icu_roots}
       PATH_SUFFIXES ${icu_data_suffixes}
       DOC "ICU ${data} data file")
-    mark_as_advanced(cache_var)
+    mark_as_advanced("${cache_var}")
     set("${data_var}" "${${cache_var}}" PARENT_SCOPE)
   endforeach()
 
index 729a503..9a62669 100644 (file)
@@ -5,43 +5,86 @@
 FindJasper
 ----------
 
-Try to find the Jasper JPEG2000 library
+Find the Jasper JPEG2000 library.
 
-Once done this will define
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
 
-::
+``Jasper::Jasper``
+  The jasper library, if found.
 
-  JASPER_FOUND - system has Jasper
-  JASPER_INCLUDE_DIR - the Jasper include directory
-  JASPER_LIBRARIES - the libraries needed to use Jasper
-  JASPER_VERSION_STRING - the version of Jasper found (since CMake 2.8.8)
-#]=======================================================================]
+Result Variables
+^^^^^^^^^^^^^^^^
 
-find_path(JASPER_INCLUDE_DIR jasper/jasper.h)
+This module defines the following variables:
+
+``JASPER_FOUND``
+  system has Jasper
+``JASPER_INCLUDE_DIRS``
+  .. versionadded:: 3.22
+
+  the Jasper include directory
+``JASPER_LIBRARIES``
+  the libraries needed to use Jasper
+``JASPER_VERSION_STRING``
+  the version of Jasper found
+
+Cache variables
+^^^^^^^^^^^^^^^
 
-if (NOT JASPER_LIBRARIES)
-    find_package(JPEG)
+The following cache variables may also be set:
 
-    find_library(JASPER_LIBRARY_RELEASE NAMES jasper libjasper)
-    find_library(JASPER_LIBRARY_DEBUG NAMES jasperd)
+``JASPER_INCLUDE_DIR``
+  where to find jasper/jasper.h, etc.
+``JASPER_LIBRARY_RELEASE``
+  where to find the Jasper library (optimized).
+``JASPER_LIBARRY_DEBUG``
+  where to find the Jasper library (debug).
+#]=======================================================================]
 
-    include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
-    SELECT_LIBRARY_CONFIGURATIONS(JASPER)
-endif ()
+find_path(JASPER_INCLUDE_DIR jasper/jasper.h)
+mark_as_advanced(JASPER_INCLUDE_DIR)
 
-if (JASPER_INCLUDE_DIR AND EXISTS "${JASPER_INCLUDE_DIR}/jasper/jas_config.h")
-    file(STRINGS "${JASPER_INCLUDE_DIR}/jasper/jas_config.h" jasper_version_str REGEX "^#define[\t ]+JAS_VERSION[\t ]+\".*\".*")
+if(NOT JASPER_LIBRARIES)
+  find_package(JPEG)
+  find_library(JASPER_LIBRARY_RELEASE NAMES jasper libjasper)
+  find_library(JASPER_LIBRARY_DEBUG NAMES jasperd)
+  include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+  select_library_configurations(JASPER)
+endif()
 
-    string(REGEX REPLACE "^#define[\t ]+JAS_VERSION[\t ]+\"([^\"]+)\".*" "\\1" JASPER_VERSION_STRING "${jasper_version_str}")
-endif ()
+if(JASPER_INCLUDE_DIR AND EXISTS "${JASPER_INCLUDE_DIR}/jasper/jas_config.h")
+  file(STRINGS "${JASPER_INCLUDE_DIR}/jasper/jas_config.h" jasper_version_str REGEX "^#define[\t ]+JAS_VERSION[\t ]+\".*\".*")
+  string(REGEX REPLACE "^#define[\t ]+JAS_VERSION[\t ]+\"([^\"]+)\".*" "\\1" JASPER_VERSION_STRING "${jasper_version_str}")
+endif()
 
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(Jasper
+find_package_handle_standard_args(Jasper
                                   REQUIRED_VARS JASPER_LIBRARIES JASPER_INCLUDE_DIR JPEG_LIBRARIES
                                   VERSION_VAR JASPER_VERSION_STRING)
 
-if (JASPER_FOUND)
-  set(JASPER_LIBRARIES ${JASPER_LIBRARIES} ${JPEG_LIBRARIES} )
-endif ()
-
-mark_as_advanced(JASPER_INCLUDE_DIR)
+if(JASPER_FOUND)
+  set(JASPER_LIBRARIES ${JASPER_LIBRARIES} ${JPEG_LIBRARIES})
+  set(JASPER_INCLUDE_DIRS ${JASPER_INCLUDE_DIR})
+  if(NOT TARGET Jasper::Jasper)
+    add_library(Jasper::Jasper UNKNOWN IMPORTED)
+    if(JASPER_INCLUDE_DIRS)
+      set_target_properties(Jasper::Jasper PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${JASPER_INCLUDE_DIRS}")
+    endif()
+    if(EXISTS "${JASPER_LIBRARY_RELEASE}")
+      set_property(TARGET Jasper::Jasper APPEND PROPERTY
+        IMPORTED CONFIGURATION RELEASE)
+      set_target_properties(Jasper::Jasper PROPERTIES
+        IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+        IMPORTED_LOCATION "${JASPER_LIBRARY_RELEASE}")
+    endif()
+    if(EXISTS "${JASPER_LIBRARY_DEBUG}")
+      set_property(TARGET Jasper::Jasper APPEND PROPERTY
+        IMPORTED CONFIGURATION DEBUG)
+      set_target_properties(Jasper::Jasper PROPERTIES
+        IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+        IMPORTED_LOCATION "${JASPER_LIBRARY_DEBUG}")
+    endif()
+  endif()
+endif()
index 3146e06..5540965 100644 (file)
@@ -35,6 +35,19 @@ The following variables may be set to influence this module's behavior:
   if set ``pkg-config`` will be used to search for a LAPACK library first
   and if one is found that is preferred
 
+``BLA_SIZEOF_INTEGER``
+  .. versionadded:: 3.22
+
+  Specify the BLAS/LAPACK library integer size:
+
+  ``4``
+    Search for a BLAS/LAPACK with 32-bit integer interfaces.
+  ``8``
+    Search for a BLAS/LAPACK with 64-bit integer interfaces.
+  ``ANY``
+    Search for any BLAS/LAPACK.
+    Most likely, a BLAS/LAPACK with 32-bit integer interfaces will be found.
+
 Imported targets
 ^^^^^^^^^^^^^^^^
 
@@ -168,9 +181,9 @@ function(CHECK_LAPACK_LIBRARIES LIBRARIES _prefix _name _flags _list _deps _addl
       list(APPEND _libraries "${_library}")
     else()
       string(REGEX REPLACE "[^A-Za-z0-9]" "_" _lib_var "${_library}")
-      set(_combined_name ${_combined_name}_${_lib_var})
+      string(APPEND _combined_name "_${_lib_var}")
       if(NOT "${_deps}" STREQUAL "")
-        set(_combined_name ${_combined_name}_deps)
+        string(APPEND _combined_name "_deps")
       endif()
       if(_libraries_work)
         find_library(${_prefix}_${_lib_var}_LIBRARY
@@ -188,7 +201,7 @@ function(CHECK_LAPACK_LIBRARIES LIBRARIES _prefix _name _flags _list _deps _addl
 
   foreach(_flag ${_flags})
     string(REGEX REPLACE "[^A-Za-z0-9]" "_" _flag_var "${_flag}")
-    set(_combined_name ${_combined_name}_${_flag_var})
+    string(APPEND _combined_name "_${_flag_var}")
   endforeach()
   if(_libraries_work)
     # Test this combination of libraries.
@@ -247,6 +260,17 @@ if(NOT (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_CO
     "FindLAPACK requires Fortran, C, or C++ to be enabled.")
 endif()
 
+if(NOT BLA_SIZEOF_INTEGER)
+  # in the reality we do not know which API of BLAS/LAPACK is masked in library
+  set(_lapack_sizeof_integer "ANY")
+elseif((BLA_SIZEOF_INTEGER STREQUAL "ANY") OR
+       (BLA_SIZEOF_INTEGER STREQUAL "4") OR
+       (BLA_SIZEOF_INTEGER STREQUAL "8"))
+  set(_lapack_sizeof_integer ${BLA_SIZEOF_INTEGER})
+else()
+  message(FATAL_ERROR "BLA_SIZEOF_INTEGER can have only <no value>, ANY, 4, or 8 values")
+endif()
+
 # Load BLAS
 if(NOT LAPACK_NOT_FOUND_MESSAGE)
   _lapack_find_dependency(BLAS)
@@ -288,17 +312,23 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
 
     _lapack_find_dependency(Threads)
 
-    if(BLA_VENDOR MATCHES "_64ilp")
+    if(_lapack_sizeof_integer EQUAL 8)
       set(LAPACK_mkl_ILP_MODE "ilp64")
-    else()
+    elseif(_lapack_sizeof_integer EQUAL 4)
       set(LAPACK_mkl_ILP_MODE "lp64")
+    else()
+      if(BLA_VENDOR MATCHES "_64ilp")
+        set(LAPACK_mkl_ILP_MODE "ilp64")
+      else()
+        set(LAPACK_mkl_ILP_MODE "lp64")
+      endif()
     endif()
 
     set(LAPACK_SEARCH_LIBS "")
 
     if(BLA_F95)
       set(LAPACK_mkl_SEARCH_SYMBOL "cheev_f95")
-      set(_LIBRARIES LAPACK95_LIBRARIES)
+      set(_LAPACK_LIBRARIES LAPACK95_LIBRARIES)
       set(_BLAS_LIBRARIES ${BLAS95_LIBRARIES})
 
       # old
@@ -311,7 +341,7 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
         "mkl_lapack95_${LAPACK_mkl_ILP_MODE}")
     else()
       set(LAPACK_mkl_SEARCH_SYMBOL "cheev")
-      set(_LIBRARIES LAPACK_LIBRARIES)
+      set(_LAPACK_LIBRARIES LAPACK_LIBRARIES)
       set(_BLAS_LIBRARIES ${BLAS_LIBRARIES})
 
       # old and new >= 10.3
@@ -350,10 +380,10 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
         "lib/${LAPACK_mkl_ARCH_NAME}"
         )
 
-    # First try empty lapack libs
-    if(NOT ${_LIBRARIES})
+    # First try empty lapack libs (implicitly linked or automatic from BLAS)
+    if(NOT ${_LAPACK_LIBRARIES})
       check_lapack_libraries(
-        ${_LIBRARIES}
+        ${_LAPACK_LIBRARIES}
         LAPACK
         ${LAPACK_mkl_SEARCH_SYMBOL}
         ""
@@ -363,18 +393,23 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
         "${LAPACK_mkl_LIB_PATH_SUFFIXES}"
         "${_BLAS_LIBRARIES}"
       )
+      if(LAPACK_WORKS AND NOT _BLAS_LIBRARIES)
+        # Give a more helpful "found" message
+        set(LAPACK_WORKS "implicitly linked")
+        set(_lapack_fphsa_req_var LAPACK_WORKS)
+      endif()
     endif()
 
     # Then try the search libs
-    foreach(IT ${LAPACK_SEARCH_LIBS})
-      string(REPLACE " " ";" SEARCH_LIBS ${IT})
-      if(NOT ${_LIBRARIES})
+    foreach(_search ${LAPACK_SEARCH_LIBS})
+      string(REPLACE " " ";" _search ${_search})
+      if(NOT ${_LAPACK_LIBRARIES})
         check_lapack_libraries(
-          ${_LIBRARIES}
+          ${_LAPACK_LIBRARIES}
           LAPACK
           ${LAPACK_mkl_SEARCH_SYMBOL}
           ""
-          "${SEARCH_LIBS}"
+          "${_search}"
           "${CMAKE_THREAD_LIBS_INIT};${LAPACK_mkl_LM};${LAPACK_mkl_LDL}"
           "${LAPACK_mkl_MKLROOT}"
           "${LAPACK_mkl_LIB_PATH_SUFFIXES}"
@@ -383,6 +418,7 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
       endif()
     endforeach()
 
+    unset(_search)
     unset(LAPACK_mkl_ILP_MODE)
     unset(LAPACK_mkl_SEARCH_SYMBOL)
     unset(LAPACK_mkl_LM)
@@ -412,48 +448,70 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
   # FlexiBLAS? (http://www.mpi-magdeburg.mpg.de/mpcsc/software/FlexiBLAS/)
   if(NOT LAPACK_LIBRARIES
       AND (BLA_VENDOR STREQUAL "FlexiBLAS" OR BLA_VENDOR STREQUAL "All"))
+    set(_lapack_flexiblas_lib "flexiblas")
+
+    if(_lapack_sizeof_integer EQUAL 8)
+      string(APPEND _lapack_flexiblas_lib "64")
+    endif()
+
     check_lapack_libraries(
       LAPACK_LIBRARIES
       LAPACK
       cheev
       ""
-      "flexiblas"
+      "${_lapack_flexiblas_lib}"
       ""
       ""
       ""
       "${BLAS_LIBRARIES}"
     )
+
+    unset(_lapack_flexiblas_lib)
   endif()
 
   # OpenBLAS? (http://www.openblas.net)
   if(NOT LAPACK_LIBRARIES
       AND (BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All"))
+    set(_lapack_openblas_lib "openblas")
+
+    if(_lapack_sizeof_integer EQUAL 8)
+      string(APPEND _lapack_openblas_lib "64")
+    endif()
+
     check_lapack_libraries(
       LAPACK_LIBRARIES
       LAPACK
       cheev
       ""
-      "openblas"
+      "${_lapack_openblas_lib}"
       ""
       ""
       ""
       "${BLAS_LIBRARIES}"
     )
+
+    unset(_lapack_openblas_lib)
   endif()
 
   # ArmPL? (https://developer.arm.com/tools-and-software/server-and-hpc/compile/arm-compiler-for-linux/arm-performance-libraries)
   if(NOT LAPACK_LIBRARIES
       AND (BLA_VENDOR MATCHES "Arm" OR BLA_VENDOR STREQUAL "All"))
     # Check for 64bit Integer support
-    if(BLA_VENDOR MATCHES "_ilp64")
+    if(_lapack_sizeof_integer EQUAL 8)
       set(LAPACK_armpl_LIB "armpl_ilp64")
-    else()
+    elseif(_lapack_sizeof_integer EQUAL 4)
       set(LAPACK_armpl_LIB "armpl_lp64")
+    else()
+      if(BLA_VENDOR MATCHES "_ilp64")
+        set(LAPACK_armpl_LIB "armpl_ilp64")
+      else()
+        set(LAPACK_armpl_LIB "armpl_lp64")
+      endif()
     endif()
 
     # Check for OpenMP support, VIA BLA_VENDOR of Arm_mp or Arm_ipl64_mp
     if(BLA_VENDOR MATCHES "_mp")
-     set(LAPACK_armpl_LIB "${LAPACK_armpl_LIB}_mp")
+      string(APPEND LAPACK_armpl_LIB "_mp")
     endif()
 
     check_lapack_libraries(
@@ -472,17 +530,50 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
   # FLAME's blis library? (https://github.com/flame/blis)
   if(NOT LAPACK_LIBRARIES
       AND (BLA_VENDOR STREQUAL "FLAME" OR BLA_VENDOR STREQUAL "All"))
+    if(_lapack_sizeof_integer EQUAL 8)
+      if(BLA_VENDOR STREQUAL "FLAME")
+        message(FATAL_ERROR "libFLAME does not support Int64 type")
+      endif()
+    else()
+      check_lapack_libraries(
+        LAPACK_LIBRARIES
+        LAPACK
+        cheev
+        ""
+        "flame"
+        ""
+        ""
+        ""
+        "${BLAS_LIBRARIES}"
+      )
+    endif()
+  endif()
+
+  # LAPACK in SCSL library? (SGI/Cray Scientific Library)
+  if(NOT LAPACK_LIBRARIES
+      AND (BLA_VENDOR MATCHES "SCSL" OR BLA_VENDOR STREQUAL "All"))
+    set(_lapack_scsl_lib "scs")
+
+    if(_lapack_sizeof_integer EQUAL 8)
+      string(APPEND _lapack_scsl_lib "_i8")
+    endif()
+    # Check for OpenMP support, VIA BLA_VENDOR of scs_mp
+    if(BLA_VENDOR MATCHES "_mp")
+      string(APPEND _lapack_scsl_lib "_mp")
+    endif()
+
     check_lapack_libraries(
       LAPACK_LIBRARIES
       LAPACK
       cheev
       ""
-      "flame"
+      "${_lapack_scsl_lib}"
       ""
       ""
       ""
       "${BLAS_LIBRARIES}"
     )
+    unset(_lapack_scsl_lib)
   endif()
 
   # BLAS in acml library?
@@ -495,105 +586,116 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
   # Apple LAPACK library?
   if(NOT LAPACK_LIBRARIES
       AND (BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All"))
-    check_lapack_libraries(
-      LAPACK_LIBRARIES
-      LAPACK
-      cheev
-      ""
-      "Accelerate"
-      ""
-      ""
-      ""
-      "${BLAS_LIBRARIES}"
-    )
+    if(_lapack_sizeof_integer EQUAL 8)
+      if(BLA_VENDOR STREQUAL "Apple")
+        message(FATAL_ERROR "Accelerate Framework does not support Int64 type")
+      endif()
+    else()
+      check_lapack_libraries(
+        LAPACK_LIBRARIES
+        LAPACK
+        cheev
+        ""
+        "Accelerate"
+        ""
+        ""
+        ""
+        "${BLAS_LIBRARIES}"
+      )
+    endif()
   endif()
 
   # Apple NAS (vecLib) library?
   if(NOT LAPACK_LIBRARIES
       AND (BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All"))
-    check_lapack_libraries(
-      LAPACK_LIBRARIES
-      LAPACK
-      cheev
-      ""
-      "vecLib"
-      ""
-      ""
-      ""
-      "${BLAS_LIBRARIES}"
-    )
+    if(_lapack_sizeof_integer EQUAL 8)
+      if(BLA_VENDOR STREQUAL "NAS")
+        message(FATAL_ERROR "Accelerate Framework does not support Int64 type")
+      endif()
+    else()
+      check_lapack_libraries(
+        LAPACK_LIBRARIES
+        LAPACK
+        cheev
+        ""
+        "vecLib"
+        ""
+        ""
+        ""
+        "${BLAS_LIBRARIES}"
+      )
+    endif()
   endif()
 
   # Elbrus Math Library?
   if(NOT LAPACK_LIBRARIES
       AND (BLA_VENDOR MATCHES "EML" OR BLA_VENDOR STREQUAL "All"))
-
-    set(LAPACK_EML_LIB "eml")
-
-    # Check for OpenMP support, VIA BLA_VENDOR of eml_mt
-    if(BLA_VENDOR MATCHES "_mt")
-     set(LAPACK_EML_LIB "${LAPACK_EML_LIB}_mt")
+    if(BLAS_LIBRARIES MATCHES "eml.+")
+      set(LAPACK_LIBRARIES ${BLAS_LIBRARIES})
     endif()
-
-    check_lapack_libraries(
-      LAPACK_LIBRARIES
-      LAPACK
-      cheev
-      ""
-      "${LAPACK_EML_LIB}"
-      ""
-      ""
-      ""
-      "${BLAS_LIBRARIES}"
-    )
   endif()
 
   # Fujitsu SSL2 Library?
   if(NOT LAPACK_LIBRARIES
       AND (BLA_VENDOR MATCHES "Fujitsu_SSL2" OR BLA_VENDOR STREQUAL "All"))
-    if(BLA_VENDOR STREQUAL "Fujitsu_SSL2BLAMP")
-      set(_ssl2_suffix BLAMP)
-    else()
-      set(_ssl2_suffix)
-    endif()
-    set(_ssl2_blas)
-    if(BLAS_LIBRARIES STREQUAL "")
-      set(_ssl2_blas "${BLAS_LINKER_FLAGS}")
-    else()
-      set(_ssl2_blas "${BLAS_LIBRARIES} ${BLAS_LINKER_FLAGS}")
+    if(BLAS_LIBRARIES MATCHES "fjlapack.+")
+      set(LAPACK_LIBRARIES ${BLAS_LIBRARIES})
+      set(LAPACK_LINKER_FLAGS ${BLAS_LINKER_FLAGS})
     endif()
-    check_lapack_libraries(
-      LAPACK_LIBRARIES
-      LAPACK
-      cheev
-      "-SSL2${_ssl2_suffix}"
-      ""
-      ""
-      ""
-      ""
-      "${_ssl2_blas}"
-    )
-    if(LAPACK_LIBRARIES)
-      set(LAPACK_LINKER_FLAGS "-SSL2${_ssl2_suffix}")
-      set(_lapack_fphsa_req_var LAPACK_LINKER_FLAGS)
+  endif()
+
+  # LAPACK in IBM ESSL library?
+  if(NOT LAPACK_LIBRARIES
+      AND (BLA_VENDOR MATCHES "IBMESSL" OR BLA_VENDOR STREQUAL "All"))
+    if(BLAS_LIBRARIES MATCHES "essl.+")
+      set(LAPACK_LIBRARIES ${BLAS_LIBRARIES})
     endif()
-    unset(_ssl2_suffix)
   endif()
 
   # NVHPC Library?
+
   if(NOT LAPACK_LIBRARIES
       AND (BLA_VENDOR MATCHES "NVHPC" OR BLA_VENDOR STREQUAL "All"))
+    set(_lapack_nvhpc_lib "lapack")
+
+    if(_lapack_sizeof_integer EQUAL 8)
+      string(APPEND _lapack_nvhpc_lib "_ilp64")
+    elseif(_lapack_sizeof_integer EQUAL 4)
+      string(APPEND _lapack_nvhpc_lib "_lp64")
+    endif()
+
     check_lapack_libraries(
       LAPACK_LIBRARIES
       LAPACK
       cheev
       ""
-      "lapack"
+      "${_lapack_nvhpc_lib}"
       "-fortranlibs"
       ""
       ""
       "${BLAS_LIBRARIES}"
     )
+
+    # an additional check for NVHPC 2020
+    # which does not have differentiation
+    # between lp64 and ilp64 modes
+    if(NOT LAPACK_LIBRARIES AND NOT _lapack_sizeof_integer EQUAL 8)
+      set(_lapack_nvhpc_lib "lapack")
+
+      check_lapack_libraries(
+        LAPACK_LIBRARIES
+        LAPACK
+        cheev
+        ""
+        "${_lapack_nvhpc_lib}"
+        "-fortranlibs"
+        ""
+        ""
+        "${BLAS_LIBRARIES}"
+      )
+    endif()
+
+    unset(_lapack_nvhpc_lib)
   endif()
 
   # Generic LAPACK library?
@@ -601,6 +703,7 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
       AND (BLA_VENDOR STREQUAL "Generic"
            OR BLA_VENDOR STREQUAL "ATLAS"
            OR BLA_VENDOR STREQUAL "All"))
+    set(_lapack_generic_lib "lapack")
     if(BLA_STATIC)
       # We do not know for sure how the LAPACK reference implementation
       # is built on this host.  Guess typical dependencies.
@@ -608,18 +711,25 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
     else()
       set(_lapack_generic_deps "")
     endif()
+
+    if(_lapack_sizeof_integer EQUAL 8)
+      string(APPEND _lapack_generic_lib "64")
+    endif()
+
     check_lapack_libraries(
       LAPACK_LIBRARIES
       LAPACK
       cheev
       ""
-      "lapack"
+      "${_lapack_generic_lib}"
       "${_lapack_generic_deps}"
       ""
       ""
       "${BLAS_LIBRARIES}"
     )
+
     unset(_lapack_generic_deps)
+    unset(_lapack_generic_lib)
   endif()
 endif()
 
@@ -646,3 +756,6 @@ if(LAPACK_LIBRARIES STREQUAL "LAPACK_LIBRARIES-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
 endif()
 
 _add_lapack_target()
+unset(_lapack_fphsa_req_var)
+unset(_lapack_sizeof_integer)
+unset(_LAPACK_LIBRARIES)
index d8f0334..c974d33 100644 (file)
@@ -105,7 +105,7 @@ This module performs a four step search for an MPI implementation:
 
 1. Search for ``MPIEXEC_EXECUTABLE`` and, if found, use its base directory.
 2. Check if the compiler has MPI support built-in. This is the case if the user passed a
-   compiler wrapper as ``CMAKE_<LANG>_COMPILER`` or if they're on a Cray system.
+   compiler wrapper as ``CMAKE_<LANG>_COMPILER`` or if they use Cray system compiler wrappers.
 3. Attempt to find an MPI compiler wrapper and determine the compiler information from it.
 4. Try to find an MPI implementation that does not ship such a wrapper by guessing settings.
    Currently, only Microsoft MPI and MPICH2 on Windows are supported.
@@ -267,6 +267,7 @@ cmake_policy(PUSH)
 cmake_policy(SET CMP0057 NEW) # if IN_LIST
 
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package(PkgConfig QUIET)
 
 # Generic compiler names
 set(_MPI_C_GENERIC_COMPILER_NAMES          mpicc    mpcc      mpicc_r mpcc_r)
@@ -333,6 +334,11 @@ set(_MPI_XL_Fortran_COMPILER_NAMES         mpixlf95   mpixlf95_r mpxlf95 mpxlf95
                                            mpixlf77   mpixlf77_r mpxlf77 mpxlf77_r
                                            mpixlf     mpixlf_r   mpxlf   mpxlf_r)
 
+# Cray Compiler names
+set(_MPI_Cray_C_COMPILER_NAMES             cc)
+set(_MPI_Cray_CXX_COMPILER_NAMES           CC)
+set(_MPI_Cray_Fortran_COMPILER_NAMES       ftn)
+
 # Prepend vendor-specific compiler wrappers to the list. If we don't know the compiler,
 # attempt all of them.
 # By attempting vendor-specific compiler names first, we should avoid situations where the compiler wrapper
@@ -488,6 +494,26 @@ function (_MPI_interrogate_compiler LANG)
     endif()
   endif()
 
+  # Cray compiler wrappers come usually without a separate mpicc/c++/ftn, but offer
+  # --cray-print-opts=...
+  if (NOT MPI_COMPILER_RETURN EQUAL 0)
+    _MPI_check_compiler(${LANG} "--cray-print-opts=cflags"
+                        MPI_COMPILE_CMDLINE MPI_COMPILER_RETURN)
+
+    if (MPI_COMPILER_RETURN EQUAL 0)
+      # Pass --no-as-needed so the mpi library is always linked. Otherwise, the
+      # Cray compiler wrapper puts an --as-needed flag around the mpi library,
+      # and it is not linked unless code directly refers to it.
+      _MPI_check_compiler(${LANG} "--no-as-needed;--cray-print-opts=libs"
+                          MPI_LINK_CMDLINE MPI_COMPILER_RETURN)
+
+      if (NOT MPI_COMPILER_RETURN EQUAL 0)
+        unset(MPI_COMPILE_CMDLINE)
+        unset(MPI_LINK_CMDLINE)
+      endif()
+    endif()
+  endif()
+
   # MPICH, MVAPICH2 and Intel MPI just use "-show". Open MPI also offers this, but the
   # -showme commands are more specialized.
   if (NOT MPI_COMPILER_RETURN EQUAL 0)
@@ -1441,9 +1467,10 @@ foreach(LANG IN ITEMS C CXX Fortran)
   endif()
   if(_MPI_FIND_${LANG})
     if( ${LANG} STREQUAL CXX AND NOT MPICXX IN_LIST MPI_FIND_COMPONENTS )
-      set(MPI_CXX_SKIP_MPICXX FALSE CACHE BOOL "If true, the MPI-2 C++ bindings are disabled using definitions.")
+      option(MPI_CXX_SKIP_MPICXX "If true, the MPI-2 C++ bindings are disabled using definitions." FALSE)
       mark_as_advanced(MPI_CXX_SKIP_MPICXX)
     endif()
+    _MPI_adjust_compile_definitions(${LANG})
     if(NOT (MPI_${LANG}_LIB_NAMES AND (MPI_${LANG}_INCLUDE_PATH OR MPI_${LANG}_INCLUDE_DIRS OR MPI_${LANG}_COMPILER_INCLUDE_DIRS)))
       set(MPI_${LANG}_TRIED_IMPLICIT FALSE)
       set(MPI_${LANG}_WORKS_IMPLICIT FALSE)
@@ -1520,10 +1547,66 @@ foreach(LANG IN ITEMS C CXX Fortran)
           endif()
         endif()
 
+        # We are on a Cray, environment identfier: PE_ENV is set (CRAY), and
+        # have NOT found an mpic++-like compiler wrapper (previous block),
+        # and we do NOT use the Cray cc/CC compiler wrappers as CC/CXX CMake
+        # compiler.
+        # So as a last resort, we now interrogate cc/CC/ftn for MPI flags.
+        if(DEFINED ENV{PE_ENV} AND NOT "${MPI_${LANG}_COMPILER}")
+          set(MPI_PINNED_COMPILER TRUE)
+          find_program(MPI_${LANG}_COMPILER
+            NAMES  ${_MPI_Cray_${LANG}_COMPILER_NAMES}
+            PATH_SUFFIXES bin sbin
+            DOC    "MPI compiler for ${LANG}"
+          )
+
+          # If we haven't made the implicit compiler test yet, perform it now.
+          if(NOT MPI_${LANG}_TRIED_IMPLICIT)
+            _MPI_create_imported_target(${LANG})
+            _MPI_check_lang_works(${LANG} TRUE)
+          endif()
+
+          set(MPI_${LANG}_WORKS_IMPLICIT TRUE)
+          _MPI_interrogate_compiler(${LANG})
+        endif()
+
         if(NOT MPI_PINNED_COMPILER AND NOT MPI_${LANG}_WRAPPER_FOUND)
           # If MPI_PINNED_COMPILER wasn't given, and the MPI compiler we potentially found didn't work, we withdraw it.
           set(MPI_${LANG}_COMPILER "MPI_${LANG}_COMPILER-NOTFOUND" CACHE FILEPATH "MPI compiler for ${LANG}" FORCE)
-          if(NOT MPI_SKIP_GUESSING)
+
+          if(LANG STREQUAL "C")
+            set(_MPI_PKG "mpi-c")
+          elseif(LANG STREQUAL "CXX")
+            set(_MPI_PKG "mpi-cxx")
+          elseif(LANG STREQUAL "Fortran")
+            set(_MPI_PKG "mpi-fort")
+          else()
+            set(_MPI_PKG "")
+          endif()
+          if(_MPI_PKG AND PKG_CONFIG_FOUND)
+            pkg_check_modules("MPI_${LANG}_PKG" "${_MPI_PKG}")
+            if("${MPI_${LANG}_PKG_FOUND}")
+              set(MPI_${LANG}_COMPILE_OPTIONS  ${MPI_${LANG}_PKG_CFLAGS}        CACHE STRING "MPI ${LANG} compilation options"       FORCE)
+              set(MPI_${LANG}_INCLUDE_PATH     ${MPI_${LANG}_PKG_INCLUDE_DIRS}  CACHE STRING "MPI ${LANG} include directories"       FORCE)
+              set(MPI_${LANG}_LINK_FLAGS       ${MPI_${LANG}_PKG_LDFLAGS}       CACHE STRING "MPI ${LANG} linker flags"              FORCE)
+              set(MPI_${LANG}_LIB_NAMES        ${MPI_${LANG}_PKG_LIBRARIES}     CACHE STRING "MPI ${LANG} libraries to link against" FORCE)
+              foreach(_MPI_LIB IN LISTS MPI_${LANG}_LIB_NAMES)
+                if(_MPI_LIB)
+                  get_filename_component(_MPI_PLAIN_LIB_NAME "${_MPI_LIB}" NAME_WE)
+                  get_filename_component(_MPI_LIB_NAME "${_MPI_LIB}" NAME)
+                  get_filename_component(_MPI_LIB_DIR "${_MPI_LIB}" DIRECTORY)
+                  find_library(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY
+                    NAMES "${_MPI_LIB_NAME}" "lib${_MPI_LIB_NAME}"
+                    HINTS ${_MPI_LIB_DIR}
+                    DOC "Location of the ${_MPI_PLAIN_LIB_NAME} library for MPI"
+                  )
+                  mark_as_advanced(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY)
+                endif()
+              endforeach()
+            endif()
+          endif()
+
+          if(NOT MPI_SKIP_GUESSING AND NOT "${MPI_${LANG}_PKG_FOUND}")
             # For C++, we may use the settings for C. Should a given compiler wrapper for C++ not exist, but one for C does, we copy over the
             # settings for C. An MPI distribution that is in this situation would be IBM Platform MPI.
             if("${LANG}" STREQUAL "CXX" AND MPI_C_WRAPPER_FOUND)
@@ -1548,7 +1631,6 @@ foreach(LANG IN ITEMS C CXX Fortran)
     endif()
     _MPI_assemble_libraries(${LANG})
 
-    _MPI_adjust_compile_definitions(${LANG})
     # We always create imported targets even if they're empty
     _MPI_create_imported_target(${LANG})
 
index 7c96d54..70d7e1d 100644 (file)
@@ -7,15 +7,15 @@
 #endif
 
 #if defined(MPI_VERSION) && defined(MPI_SUBVERSION)
-const char mpiver_str[] = { 'I', 'N',
-                            'F', 'O',
-                            ':', 'M',
-                            'P', 'I',
-                            '-', 'V',
-                            'E', 'R',
-                            '[', ('0' + MPI_VERSION),
-                            '.', ('0' + MPI_SUBVERSION),
-                            ']', '\0' };
+const static char mpiver_str[] = { 'I', 'N',
+                                   'F', 'O',
+                                   ':', 'M',
+                                   'P', 'I',
+                                   '-', 'V',
+                                   'E', 'R',
+                                   '[', ('0' + MPI_VERSION),
+                                   '.', ('0' + MPI_SUBVERSION),
+                                   ']', '\0' };
 #endif
 
 int main(int argc, char* argv[])
index e7cd834..0ca593e 100644 (file)
@@ -93,6 +93,33 @@ behavior:
   additional versions of Matlab for the automatic retrieval of the installed
   versions.
 
+Imported targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.22
+
+This module defines the following :prop_tgt:`IMPORTED` targets:
+
+``Matlab::mex``
+  The ``mex`` library, always available.
+
+``Matlab::mx``
+  The mx library of Matlab (arrays), always available.
+
+``Matlab::eng``
+  Matlab engine library. Available only if the ``ENG_LIBRARY`` component
+  is requested.
+
+``Matlab::mat``
+  Matlab matrix library. Available only if the ``MAT_LIBRARY`` component
+  is requested.
+
+``Matlab::MatlabEngine``
+  Matlab C++ engine library, always available for R2018a and newer.
+
+``Matlab::MatlabDataArray``
+  Matlab C++ data array library, always available for R2018a and newer.
+
 Variables defined by the module
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -451,7 +478,7 @@ function(matlab_extract_all_installed_versions_from_registry win64 matlab_versio
 
   if(matlabs_from_registry)
     list(REMOVE_DUPLICATES matlabs_from_registry)
-    list(SORT matlabs_from_registry)
+    list(SORT matlabs_from_registry COMPARE NATURAL)
     list(REVERSE matlabs_from_registry)
   endif()
 
@@ -495,7 +522,7 @@ macro(extract_matlab_versions_from_registry_brute_force matlab_versions)
   # we order from more recent to older
   if(matlab_supported_versions)
     list(REMOVE_DUPLICATES matlab_supported_versions)
-    list(SORT matlab_supported_versions)
+    list(SORT matlab_supported_versions COMPARE NATURAL)
     list(REVERSE matlab_supported_versions)
   endif()
 
@@ -1545,6 +1572,29 @@ if(_numbers_of_matlab_roots GREATER 0)
     list(GET _matlab_possible_roots ${_matlab_or_mcr_index} Matlab_Or_MCR)
     list(GET _matlab_possible_roots ${_list_index} Matlab_VERSION_STRING)
     list(GET _matlab_possible_roots ${_matlab_root_dir_index} Matlab_ROOT_DIR)
+  elseif(DEFINED Matlab_FIND_VERSION)
+    foreach(_matlab_root_index RANGE 1 ${_numbers_of_matlab_roots} 3)
+      list(GET _matlab_possible_roots ${_matlab_root_index} _matlab_root_version)
+      if(_matlab_root_version VERSION_GREATER_EQUAL Matlab_FIND_VERSION)
+        set(_list_index ${_matlab_root_index})
+        break()
+      endif()
+    endforeach()
+
+    if(_list_index LESS 0)
+      set(_list_index 1)
+    endif()
+
+    math(EXPR _matlab_or_mcr_index "${_list_index} - 1")
+    math(EXPR _matlab_root_dir_index "${_list_index} + 1")
+    list(GET _matlab_possible_roots ${_matlab_or_mcr_index} Matlab_Or_MCR)
+    list(GET _matlab_possible_roots ${_list_index} Matlab_VERSION_STRING)
+    list(GET _matlab_possible_roots ${_matlab_root_dir_index} Matlab_ROOT_DIR)
+    # adding a warning in case of ambiguity
+    if(_numbers_of_matlab_roots GREATER 3 AND MATLAB_FIND_DEBUG)
+      message(WARNING "[MATLAB] Found several distributions of Matlab. Setting the current version to ${Matlab_VERSION_STRING} (located ${Matlab_ROOT_DIR})."
+                      " If this is not the desired behavior, use the EXACT keyword or provide the -DMatlab_ROOT_DIR=... on the command line")
+    endif()
   else()
     list(GET _matlab_possible_roots 0 Matlab_Or_MCR)
     list(GET _matlab_possible_roots 1 Matlab_VERSION_STRING)
@@ -1866,6 +1916,32 @@ if(Matlab_DATAARRAY_LIBRARY)
   list(APPEND Matlab_LIBRARIES ${Matlab_DATAARRAY_LIBRARY})
 endif()
 
+# internal
+# This small stub permits to add imported targets for the found MATLAB libraries
+function(_Matlab_add_imported_target _matlab_library_variable_name _matlab_library_target_name)
+  if(Matlab_${_matlab_library_variable_name}_LIBRARY)
+    if(NOT TARGET Matlab::${_matlab_library_target_name})
+      add_library(Matlab::${_matlab_library_target_name} UNKNOWN IMPORTED)
+      set_target_properties(Matlab::${_matlab_library_target_name} PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${Matlab_INCLUDE_DIRS}"
+        IMPORTED_LOCATION "${Matlab_${_matlab_library_variable_name}_LIBRARY}")
+      if(_matlab_library_target_name STREQUAL "mex" OR
+         _matlab_library_target_name STREQUAL "eng" OR
+         _matlab_library_target_name STREQUAL "mat")
+        set_target_properties(Matlab::${_matlab_library_target_name} PROPERTIES
+          INTERFACE_LINK_LIBRARIES Matlab::mx)
+      endif()
+    endif()
+  endif()
+endfunction()
+
+_Matlab_add_imported_target(MX mx)
+_Matlab_add_imported_target(MEX mex)
+_Matlab_add_imported_target(ENG eng)
+_Matlab_add_imported_target(MAT mat)
+_Matlab_add_imported_target(ENGINE MatlabEngine)
+_Matlab_add_imported_target(DATAARRAY MatlabDataArray)
+
 find_package_handle_standard_args(
   Matlab
   FOUND_VAR Matlab_FOUND
index 4108651..f4fe4a6 100644 (file)
@@ -43,7 +43,7 @@ endif()
 
 # First search the PATH
 find_program(Patch_EXECUTABLE
-  NAME patch
+  NAMES patch
   PATHS ${_patch_path}
   DOC ${_doc}
   )
index 01ad5ac..ef43a3a 100644 (file)
@@ -12,11 +12,24 @@ Finds the ``pkg-config`` executable and adds the :command:`pkg_get_variable`,
 following variables will also be set:
 
 ``PKG_CONFIG_FOUND``
-  if pkg-config executable was found
-``PKG_CONFIG_EXECUTABLE``
-  pathname of the pkg-config program
+  True if a pkg-config executable was found.
+
 ``PKG_CONFIG_VERSION_STRING``
-  version of pkg-config (since CMake 2.8.8)
+  .. versionadded:: 2.8.8
+
+  The version of pkg-config that was found.
+
+``PKG_CONFIG_EXECUTABLE``
+  The pathname of the pkg-config program.
+
+``PKG_CONFIG_ARGN``
+  .. versionadded:: 3.22
+
+  A list of arguments to pass to pkg-config.
+
+Both ``PKG_CONFIG_EXECUTABLE`` and ``PKG_CONFIG_ARGN`` are initialized by the
+module, but may be overridden by the user.  See `Variables Affecting Behavior`_
+for how these variables are initialized.
 
 #]========================================]
 
@@ -29,13 +42,22 @@ set(PKG_CONFIG_VERSION 1)
 
 # find pkg-config, use PKG_CONFIG if set
 if((NOT PKG_CONFIG_EXECUTABLE) AND (NOT "$ENV{PKG_CONFIG}" STREQUAL ""))
-  set(PKG_CONFIG_EXECUTABLE "$ENV{PKG_CONFIG}" CACHE FILEPATH "pkg-config executable")
+  separate_arguments(PKG_CONFIG_FROM_ENV_SPLIT NATIVE_COMMAND PROGRAM SEPARATE_ARGS "$ENV{PKG_CONFIG}")
+  list(LENGTH PKG_CONFIG_FROM_ENV_SPLIT PKG_CONFIG_FROM_ENV_SPLIT_ARGC)
+  if(PKG_CONFIG_FROM_ENV_SPLIT_ARGC GREATER 0)
+    list(GET PKG_CONFIG_FROM_ENV_SPLIT 0 PKG_CONFIG_FROM_ENV_ARGV0)
+    if(PKG_CONFIG_FROM_ENV_SPLIT_ARGC GREATER 1)
+      list(SUBLIST PKG_CONFIG_FROM_ENV_SPLIT 1 -1 PKG_CONFIG_ARGN)
+    endif()
+    set(PKG_CONFIG_EXECUTABLE "${PKG_CONFIG_FROM_ENV_ARGV0}" CACHE FILEPATH "pkg-config executable")
+  endif()
 endif()
 
 set(PKG_CONFIG_NAMES "pkg-config")
 if(CMAKE_HOST_WIN32)
   list(PREPEND PKG_CONFIG_NAMES "pkg-config.bat")
 endif()
+list(PREPEND PKG_CONFIG_NAMES "pkgconf")
 
 find_program(PKG_CONFIG_EXECUTABLE
   NAMES ${PKG_CONFIG_NAMES}
@@ -43,9 +65,12 @@ find_program(PKG_CONFIG_EXECUTABLE
   DOC "pkg-config executable")
 mark_as_advanced(PKG_CONFIG_EXECUTABLE)
 
+set(PKG_CONFIG_ARGN "${PKG_CONFIG_ARGN}" CACHE STRING "Arguments to supply to pkg-config")
+mark_as_advanced(PKG_CONFIG_ARGN)
+
 set(_PKG_CONFIG_FAILURE_MESSAGE "")
 if (PKG_CONFIG_EXECUTABLE)
-  execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --version
+  execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} ${PKG_CONFIG_ARGN} --version
     OUTPUT_VARIABLE PKG_CONFIG_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE
     ERROR_VARIABLE _PKG_CONFIG_VERSION_ERROR ERROR_STRIP_TRAILING_WHITESPACE
     RESULT_VARIABLE _PKG_CONFIG_VERSION_RESULT
@@ -53,14 +78,18 @@ if (PKG_CONFIG_EXECUTABLE)
 
   if (NOT _PKG_CONFIG_VERSION_RESULT EQUAL 0)
     string(REPLACE "\n" "\n    " _PKG_CONFIG_VERSION_ERROR "      ${_PKG_CONFIG_VERSION_ERROR}")
+    if(PKG_CONFIG_ARGN)
+      string(REPLACE ";" " " PKG_CONFIG_ARGN " ${PKG_CONFIG_ARGN}")
+    endif()
     string(APPEND _PKG_CONFIG_FAILURE_MESSAGE
       "The command\n"
-      "      \"${PKG_CONFIG_EXECUTABLE}\" --version\n"
+      "      \"${PKG_CONFIG_EXECUTABLE}\"${PKG_CONFIG_ARGN} --version\n"
       "    failed with output:\n${PKG_CONFIG_VERSION_STRING}\n"
       "    stderr: \n${_PKG_CONFIG_VERSION_ERROR}\n"
       "    result: \n${_PKG_CONFIG_VERSION_RESULT}"
       )
     set(PKG_CONFIG_EXECUTABLE "")
+    set(PKG_CONFIG_ARGN "")
     unset(PKG_CONFIG_VERSION_STRING)
   endif ()
   unset(_PKG_CONFIG_VERSION_RESULT)
@@ -99,7 +128,7 @@ macro(_pkgconfig_invoke _pkglist _prefix _varname _regexp)
   set(_pkgconfig_invoke_result)
 
   execute_process(
-    COMMAND ${PKG_CONFIG_EXECUTABLE} ${ARGN} ${_pkglist}
+    COMMAND ${PKG_CONFIG_EXECUTABLE} ${PKG_CONFIG_ARGN} ${ARGN} ${_pkglist}
     OUTPUT_VARIABLE _pkgconfig_invoke_result
     RESULT_VARIABLE _pkgconfig_failed
     OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -393,6 +422,14 @@ macro(_pkg_set_path_internal)
     unset(_lib_dirs)
     unset(_pkgconfig_path)
   endif()
+
+  # Tell pkg-config not to strip any -L paths so we can search them all.
+  if(DEFINED ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS})
+    set(_pkgconfig_allow_system_libs_old "$ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS}")
+  else()
+    unset(_pkgconfig_allow_system_libs_old)
+  endif()
+  set(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS} 0)
 endmacro()
 
 macro(_pkg_restore_path_internal)
@@ -400,6 +437,10 @@ macro(_pkg_restore_path_internal)
     # Restore the environment variable
     set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path_old}")
   endif()
+  if(DEFINED _pkgconfig_allow_system_libs_old)
+    set(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS} "${_pkgconfig_allow_system_libs_old}")
+    unset(_pkgconfig_allow_system_libs_old)
+  endif()
 
   unset(_extra_paths)
   unset(_pkgconfig_path_old)
@@ -541,7 +582,7 @@ macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cma
 
       # execute the query
       execute_process(
-        COMMAND ${PKG_CONFIG_EXECUTABLE} ${_pkg_check_modules_exist_query}
+        COMMAND ${PKG_CONFIG_EXECUTABLE} ${PKG_CONFIG_ARGN} ${_pkg_check_modules_exist_query}
         RESULT_VARIABLE _pkgconfig_retval
         ERROR_VARIABLE _pkgconfig_error
         ERROR_STRIP_TRAILING_WHITESPACE)
@@ -893,12 +934,30 @@ Variables Affecting Behavior
 
 .. variable:: PKG_CONFIG_EXECUTABLE
 
-  This can be set to the path of the pkg-config executable.  If not provided,
-  it will be set by the module as a result of calling :command:`find_program`
-  internally.
+  This cache variable can be set to the path of the pkg-config executable.
+  :command:`find_program` is called internally by the module with this
+  variable.
 
   .. versionadded:: 3.1
-    The ``PKG_CONFIG`` environment variable can be used as a hint.
+    The ``PKG_CONFIG`` environment variable can be used as a hint if
+    ``PKG_CONFIG_EXECUTABLE`` has not yet been set.
+
+  .. versionchanged:: 3.22
+    If the ``PKG_CONFIG`` environment variable is set, only the first
+    argument is taken from it when using it as a hint.
+
+.. variable:: PKG_CONFIG_ARGN
+
+  .. versionadded:: 3.22
+
+  This cache variable can be set to a list of arguments to additionally pass
+  to pkg-config if needed. If not provided, it will be initialized from the
+  ``PKG_CONFIG`` environment variable, if set. The first argument in that
+  environment variable is assumed to be the pkg-config program, while all
+  remaining arguments after that are used to initialize ``PKG_CONFIG_ARGN``.
+  If no such environment variable is defined, ``PKG_CONFIG_ARGN`` is
+  initialized to an empty string. The module does not update the variable once
+  it has been set in the cache.
 
 .. variable:: PKG_CONFIG_USE_CMAKE_PREFIX_PATH
 
index c6a3451..e4d6cf3 100644 (file)
@@ -106,7 +106,7 @@ endmacro()
 # Do NOT even think about using it outside of this file!
 macro(_check_pthreads_flag)
   if(NOT Threads_FOUND)
-    # If we did not found -lpthread, -lpthread, or -lthread, look for -pthread
+    # If we did not find -lpthreads, -lpthread, or -lthread, look for -pthread
     if(NOT DEFINED THREADS_HAVE_PTHREAD_ARG)
       message(CHECK_START "Check if compiler accepts -pthread")
       if(CMAKE_C_COMPILER_LOADED)
index d480fc4..fd5ee53 100644 (file)
@@ -828,6 +828,12 @@ if (UNIX)
     X11_Xau_INCLUDE_PATH
     X11_xcb_LIB
     X11_xcb_INCLUDE_PATH
+    X11_xcb_icccm_LIB
+    X11_xcb_icccm_INCLUDE_PATH
+    X11_xcb_util_LIB
+    X11_xcb_util_INCLUDE_PATH
+    X11_xcb_xfixes_LIB
+    X11_xcb_xfixes_INCLUDE_PATH
     X11_xcb_xkb_LIB
     X11_X11_xcb_LIB
     X11_X11_xcb_INCLUDE_PATH
index 4aaad79..6ca424a 100644 (file)
@@ -218,6 +218,7 @@ if(NOT DEFINED CMAKE_INSTALL_LIBDIR OR (_libdir_set
   # Override this default 'lib' with 'lib64' iff:
   #  - we are on Linux system but NOT cross-compiling
   #  - we are NOT on debian
+  #  - we are NOT building for conda
   #  - we are on a 64 bits system
   # reason is: amd64 ABI: https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI
   # For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
@@ -239,11 +240,34 @@ if(NOT DEFINED CMAKE_INSTALL_LIBDIR OR (_libdir_set
       "Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
       "Please enable at least one language before including GNUInstallDirs.")
   endif()
+
   if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
-      AND NOT CMAKE_CROSSCOMPILING
-      AND NOT EXISTS "/etc/alpine-release"
-      AND NOT EXISTS "/etc/arch-release")
-    if (EXISTS "/etc/debian_version") # is this a debian system ?
+      AND NOT CMAKE_CROSSCOMPILING)
+    unset(__system_type_for_install)
+    if(DEFINED ENV{CONDA_BUILD} AND DEFINED ENV{PREFIX})
+      set(conda_prefix "$ENV{PREFIX}")
+      cmake_path(ABSOLUTE_PATH conda_prefix NORMALIZE)
+      if("${CMAKE_INSTALL_PREFIX}" STREQUAL conda_prefix)
+        set(__system_type_for_install "conda")
+      endif()
+    elseif(DEFINED ENV{CONDA_PREFIX})
+      set(conda_prefix "$ENV{CONDA_PREFIX}")
+      cmake_path(ABSOLUTE_PATH conda_prefix NORMALIZE)
+      if("${CMAKE_INSTALL_PREFIX}" STREQUAL conda_prefix)
+        set(__system_type_for_install "conda")
+      endif()
+    endif()
+    if(NOT __system_type_for_install)
+      if (EXISTS "/etc/alpine-release")
+        set(__system_type_for_install "alpine")
+      elseif (EXISTS "/etc/arch-release")
+        set(__system_type_for_install "arch linux")
+      elseif (EXISTS "/etc/debian_version")
+        set(__system_type_for_install "debian")
+      endif()
+    endif()
+
+    if(__system_type_for_install STREQUAL "debian")
       if(CMAKE_LIBRARY_ARCHITECTURE)
         if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$")
           set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
@@ -253,7 +277,8 @@ if(NOT DEFINED CMAKE_INSTALL_LIBDIR OR (_libdir_set
           set(__LAST_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
         endif()
       endif()
-    else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
+    elseif(NOT DEFINED __system_type_for_install)
+      # not debian, alpine, arch, or conda so rely on CMAKE_SIZEOF_VOID_P:
       if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
         set(_LIBDIR_DEFAULT "lib64")
         if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX)
@@ -262,6 +287,8 @@ if(NOT DEFINED CMAKE_INSTALL_LIBDIR OR (_libdir_set
       endif()
     endif()
   endif()
+  unset(__system_type_for_install)
+
   if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
     set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "Object code libraries (${_LIBDIR_DEFAULT})")
   elseif(DEFINED __LAST_LIBDIR_DEFAULT
index e90a9b5..53584c6 100644 (file)
@@ -746,7 +746,7 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
     set(gp_regex_error "")
     set(gp_regex_fallback "")
     set(gp_regex_cmp_count 1)
-  elseif(gp_tool MATCHES "objdump$")
+  elseif(gp_tool MATCHES "objdump(\\.exe)?$")
     set(gp_cmd_args "-p")
     set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$")
     set(gp_regex_error "")
index 80d8e23..f5f4f02 100644 (file)
@@ -151,6 +151,7 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
                          [WORKING_DIRECTORY dir]
                          [TEST_PREFIX prefix]
                          [TEST_SUFFIX suffix]
+                         [TEST_FILTER expr]
                          [NO_PRETTY_TYPES] [NO_PRETTY_VALUES]
                          [PROPERTIES name1 value1...]
                          [TEST_LIST var]
@@ -204,6 +205,15 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
     every discovered test case.  Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
     be specified.
 
+  ``TEST_FILTER expr``
+    .. versionadded:: 3.22
+
+    Filter expression to pass as a ``--gtest_filter`` argument during test
+    discovery.  Note that the expression is a wildcard-based format that
+    matches against the original test names as used by gtest.  For type or
+    value-parameterized tests, these names may be different to the potentially
+    pretty-printed test names that ``ctest`` uses.
+
   ``NO_PRETTY_TYPES``
     By default, the type index of type-parameterized tests is replaced by the
     actual type name in the CTest test name.  If this behavior is undesirable
@@ -411,7 +421,7 @@ function(gtest_discover_tests TARGET)
     ""
     "NO_PRETTY_TYPES;NO_PRETTY_VALUES"
     "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;DISCOVERY_TIMEOUT;XML_OUTPUT_DIR;DISCOVERY_MODE"
-    "EXTRA_ARGS;PROPERTIES"
+    "EXTRA_ARGS;PROPERTIES;TEST_FILTER"
     ${ARGN}
   )
 
@@ -475,6 +485,7 @@ function(gtest_discover_tests TARGET)
               -D "TEST_PROPERTIES=${_PROPERTIES}"
               -D "TEST_PREFIX=${_TEST_PREFIX}"
               -D "TEST_SUFFIX=${_TEST_SUFFIX}"
+              -D "TEST_FILTER=${_TEST_FILTER}"
               -D "NO_PRETTY_TYPES=${_NO_PRETTY_TYPES}"
               -D "NO_PRETTY_VALUES=${_NO_PRETTY_VALUES}"
               -D "TEST_LIST=${_TEST_LIST}"
@@ -505,7 +516,8 @@ function(gtest_discover_tests TARGET)
     string(CONCAT ctest_include_content
       "if(EXISTS \"$<TARGET_FILE:${TARGET}>\")"                                    "\n"
       "  if(NOT EXISTS \"${ctest_tests_file}\" OR"                                 "\n"
-      "     NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"$<TARGET_FILE:${TARGET}>\")" "\n"
+      "     NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"$<TARGET_FILE:${TARGET}>\" OR\n"
+      "     NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"\${CMAKE_CURRENT_LIST_FILE}\")\n"
       "    include(\"${_GOOGLETEST_DISCOVER_TESTS_SCRIPT}\")"                      "\n"
       "    gtest_discover_tests_impl("                                             "\n"
       "      TEST_EXECUTABLE"        " [==[" "$<TARGET_FILE:${TARGET}>"   "]==]"   "\n"
@@ -515,6 +527,7 @@ function(gtest_discover_tests TARGET)
       "      TEST_PROPERTIES"        " [==[" "${_PROPERTIES}"             "]==]"   "\n"
       "      TEST_PREFIX"            " [==[" "${_TEST_PREFIX}"            "]==]"   "\n"
       "      TEST_SUFFIX"            " [==[" "${_TEST_SUFFIX}"            "]==]"   "\n"
+      "      TEST_FILTER"            " [==[" "${_TEST_FILTER}"            "]==]"   "\n"
       "      NO_PRETTY_TYPES"        " [==[" "${_NO_PRETTY_TYPES}"        "]==]"   "\n"
       "      NO_PRETTY_VALUES"       " [==[" "${_NO_PRETTY_VALUES}"       "]==]"   "\n"
       "      TEST_LIST"              " [==[" "${_TEST_LIST}"              "]==]"   "\n"
index 0f79c9a..6b3bf34 100644 (file)
@@ -44,7 +44,7 @@ function(gtest_discover_tests_impl)
   cmake_parse_arguments(
     ""
     ""
-    "NO_PRETTY_TYPES;NO_PRETTY_VALUES;TEST_EXECUTABLE;TEST_WORKING_DIR;TEST_PREFIX;TEST_SUFFIX;TEST_LIST;CTEST_FILE;TEST_DISCOVERY_TIMEOUT;TEST_XML_OUTPUT_DIR"
+    "NO_PRETTY_TYPES;NO_PRETTY_VALUES;TEST_EXECUTABLE;TEST_WORKING_DIR;TEST_PREFIX;TEST_SUFFIX;TEST_LIST;CTEST_FILE;TEST_DISCOVERY_TIMEOUT;TEST_XML_OUTPUT_DIR;TEST_FILTER"
     "TEST_EXTRA_ARGS;TEST_PROPERTIES;TEST_EXECUTOR"
     ${ARGN}
   )
@@ -58,6 +58,12 @@ function(gtest_discover_tests_impl)
   set(tests)
   set(tests_buffer)
 
+  if(_TEST_FILTER)
+    set(filter "--gtest_filter=${_TEST_FILTER}")
+  else()
+    set(filter)
+  endif()
+
   # Run test executable to get list of available tests
   if(NOT EXISTS "${_TEST_EXECUTABLE}")
     message(FATAL_ERROR
@@ -66,7 +72,7 @@ function(gtest_discover_tests_impl)
     )
   endif()
   execute_process(
-    COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" --gtest_list_tests
+    COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" --gtest_list_tests ${filter}
     WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
     TIMEOUT ${_TEST_DISCOVERY_TIMEOUT}
     OUTPUT_VARIABLE output
@@ -178,6 +184,7 @@ if(CMAKE_SCRIPT_MODE_FILE)
     TEST_WORKING_DIR ${TEST_WORKING_DIR}
     TEST_PREFIX ${TEST_PREFIX}
     TEST_SUFFIX ${TEST_SUFFIX}
+    TEST_FILTER ${TEST_FILTER}
     TEST_LIST ${TEST_LIST}
     CTEST_FILE ${CTEST_FILE}
     TEST_DISCOVERY_TIMEOUT ${TEST_DISCOVERY_TIMEOUT}
index a267278..689cab5 100644 (file)
@@ -73,6 +73,8 @@ set(_IRSL_HAVE_MSVC FALSE)
 foreach(LANG IN ITEMS C CXX Fortran)
   if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "Intel")
     if(NOT _IRSL_HAVE_Intel)
+      # The oneAPI icx/ifx compilers are under ${os}/bin.
+      # The classic icc/icpc/icl/ifort compilers may be under ${os}/bin/intel64.
       get_filename_component(_Intel_basedir "${CMAKE_${LANG}_COMPILER}" PATH)
       if(CMAKE_SIZEOF_VOID_P EQUAL 8)
         set(_Intel_archdir intel64)
@@ -80,19 +82,36 @@ foreach(LANG IN ITEMS C CXX Fortran)
         set(_Intel_archdir ia32)
       endif()
       set(_Intel_compiler_ver ${CMAKE_${LANG}_COMPILER_VERSION})
-      if(WIN32 AND EXISTS "${_Intel_basedir}/../redist/${_Intel_archdir}_win/compiler")
-        get_filename_component(_Intel_redistdir "${_Intel_basedir}/../redist/${_Intel_archdir}_win/compiler" ABSOLUTE)
-      elseif(WIN32)
-        get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../redist/${_Intel_archdir}/compiler" ABSOLUTE)
+      if(WIN32)
+        set(_Intel_possible_redistdirs
+          "${_Intel_basedir}/../redist/${_Intel_archdir}_win/compiler"
+          "${_Intel_basedir}/../redist/${_Intel_archdir}/compiler"
+          "${_Intel_basedir}/../../redist/${_Intel_archdir}_win/compiler"
+          "${_Intel_basedir}/../../redist/${_Intel_archdir}/compiler"
+          )
       elseif(APPLE)
-        get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../compiler/lib" ABSOLUTE)
+        set(_Intel_possible_redistdirs
+          "${_Intel_basedir}/../../compiler/lib"
+          )
       else()
-        if(EXISTS "${_Intel_basedir}/../lib/${_Intel_archdir}_lin")
-          get_filename_component(_Intel_redistdir "${_Intel_basedir}/../lib/${_Intel_archdir}" ABSOLUTE)
-        else()
-          get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../compiler/lib/${_Intel_archdir}_lin" ABSOLUTE)
+        set(_Intel_possible_redistdirs
+          "${_Intel_basedir}/../lib/${_Intel_archdir}"
+          "${_Intel_basedir}/../../compiler/lib/${_Intel_archdir}_lin"
+          )
+      endif()
+
+      set(_Intel_redistdir NOT-FOUND)
+      foreach(dir IN LISTS _Intel_possible_redistdirs)
+        if(EXISTS "${dir}")
+          set(_Intel_redistdir "${dir}")
+          break()
         endif()
+      endforeach()
+      # Fall back to last dir
+      if(NOT _Intel_redistdir)
+        list(POP_BACK _Intel_possible_redistdirs _Intel_redistdir)
       endif()
+      unset(_Intel_possible_redistdirs)
       set(_IRSL_HAVE_Intel TRUE)
     endif()
   elseif("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "MSVC")
index 967ad7b..c115f00 100644 (file)
@@ -662,10 +662,12 @@ function(cpack_deb_prepare_package_vars)
 
   # add ldconfig call in default postrm and postint
   set(CPACK_ADD_LDCONFIG_CALL 0)
+  # all files in CPACK_DEB_SHARED_OBJECT_FILES have dot at the beginning
+  set(_LDCONF_DEFAULTS "./lib" "./usr/lib")
   foreach(_FILE IN LISTS CPACK_DEB_SHARED_OBJECT_FILES)
     get_filename_component(_DIR ${_FILE} DIRECTORY)
-    # all files in CPACK_DEB_SHARED_OBJECT_FILES have dot at the beginning
-    if(_DIR STREQUAL "./lib" OR _DIR STREQUAL "./usr/lib")
+    get_filename_component(_PARENT_DIR ${_DIR} DIRECTORY)
+    if(_DIR IN_LIST _LDCONF_DEFAULTS OR _PARENT_DIR IN_LIST _LDCONF_DEFAULTS)
       set(CPACK_ADD_LDCONFIG_CALL 1)
     endif()
   endforeach()
index cbd748b..c72bf6d 100644 (file)
@@ -1160,6 +1160,16 @@ function(cpack_rpm_generate_package)
     set(TMP_RPM_SPEC_INSTALL_POST "%define __spec_install_post ${CPACK_RPM_SPEC_INSTALL_POST}")
   endif()
 
+  # CPACK_RPM_REQUIRES_EXCLUDE_FROM
+  # May be defined to keep the dependency generator from
+  # scanning specific files or directories for deps.
+  if(CPACK_RPM_REQUIRES_EXCLUDE_FROM)
+    if(CPACK_RPM_PACKAGE_DEBUG)
+      message("CPackRPM:Debug: User defined CPACK_RPM_REQUIRES_EXCLUDE_FROM = ${CPACK_RPM_REQUIRES_EXCLUDE_FROM}")
+    endif()
+    set(TMP_RPM_REQUIRES_EXCLUDE_FROM "%global __requires_exclude_from ${CPACK_RPM_REQUIRES_EXCLUDE_FROM}")
+  endif()
+
   # CPACK_RPM_POST_INSTALL_SCRIPT_FILE (or CPACK_RPM_<COMPONENT>_POST_INSTALL_SCRIPT_FILE)
   # CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE (or CPACK_RPM_<COMPONENT>_POST_UNINSTALL_SCRIPT_FILE)
   # CPACK_RPM_POST_TRANS_SCRIPT_FILE (or CPACK_RPM_<COMPONENT>_POST_TRANS_SCRIPT_FILE)
@@ -1648,6 +1658,7 @@ Vendor:         \@CPACK_RPM_PACKAGE_VENDOR\@
 \@FILE_NAME_DEFINE\@
 %define _unpackaged_files_terminate_build 0
 \@TMP_RPM_SPEC_INSTALL_POST\@
+\@TMP_RPM_REQUIRES_EXCLUDE_FROM\@
 \@CPACK_RPM_SPEC_MORE_DEFINE\@
 \@CPACK_RPM_COMPRESSION_TYPE_TMP\@
 
@@ -1782,6 +1793,7 @@ Vendor:         \@CPACK_RPM_PACKAGE_VENDOR\@
 \@FILE_NAME_DEFINE\@
 %define _unpackaged_files_terminate_build 0
 \@TMP_RPM_SPEC_INSTALL_POST\@
+\@TMP_RPM_REQUIRES_EXCLUDE_FROM\@
 \@CPACK_RPM_SPEC_MORE_DEFINE\@
 \@CPACK_RPM_COMPRESSION_TYPE_TMP\@
 
index 0a9c487..8a0c972 100644 (file)
@@ -540,7 +540,7 @@ FunctionEnd
   @CPACK_NSIS_INSTALLER_WELCOME_TITLE_3LINES_CODE@
   !insertmacro MUI_PAGE_WELCOME
 
-  !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
+  @CPACK_NSIS_LICENSE_PAGE@
   Page custom InstallOptionsPage
   !insertmacro MUI_PAGE_DIRECTORY
 
@@ -564,21 +564,27 @@ FunctionEnd
 ;Languages
 
   !insertmacro MUI_LANGUAGE "English" ;first language is the default language
+  !insertmacro MUI_LANGUAGE "Afrikaans"
   !insertmacro MUI_LANGUAGE "Albanian"
   !insertmacro MUI_LANGUAGE "Arabic"
+  !insertmacro MUI_LANGUAGE "Asturian"
   !insertmacro MUI_LANGUAGE "Basque"
   !insertmacro MUI_LANGUAGE "Belarusian"
   !insertmacro MUI_LANGUAGE "Bosnian"
   !insertmacro MUI_LANGUAGE "Breton"
   !insertmacro MUI_LANGUAGE "Bulgarian"
+  !insertmacro MUI_LANGUAGE "Catalan"
+  !insertmacro MUI_LANGUAGE "Corsican"
   !insertmacro MUI_LANGUAGE "Croatian"
   !insertmacro MUI_LANGUAGE "Czech"
   !insertmacro MUI_LANGUAGE "Danish"
   !insertmacro MUI_LANGUAGE "Dutch"
+  !insertmacro MUI_LANGUAGE "Esperanto"
   !insertmacro MUI_LANGUAGE "Estonian"
   !insertmacro MUI_LANGUAGE "Farsi"
   !insertmacro MUI_LANGUAGE "Finnish"
   !insertmacro MUI_LANGUAGE "French"
+  !insertmacro MUI_LANGUAGE "Galician"
   !insertmacro MUI_LANGUAGE "German"
   !insertmacro MUI_LANGUAGE "Greek"
   !insertmacro MUI_LANGUAGE "Hebrew"
@@ -597,22 +603,29 @@ FunctionEnd
   !insertmacro MUI_LANGUAGE "Malay"
   !insertmacro MUI_LANGUAGE "Mongolian"
   !insertmacro MUI_LANGUAGE "Norwegian"
+  !insertmacro MUI_LANGUAGE "NorwegianNynorsk"
+  !insertmacro MUI_LANGUAGE "Pashto"
   !insertmacro MUI_LANGUAGE "Polish"
   !insertmacro MUI_LANGUAGE "Portuguese"
   !insertmacro MUI_LANGUAGE "PortugueseBR"
   !insertmacro MUI_LANGUAGE "Romanian"
   !insertmacro MUI_LANGUAGE "Russian"
+  !insertmacro MUI_LANGUAGE "ScotsGaelic"
   !insertmacro MUI_LANGUAGE "Serbian"
   !insertmacro MUI_LANGUAGE "SerbianLatin"
   !insertmacro MUI_LANGUAGE "SimpChinese"
   !insertmacro MUI_LANGUAGE "Slovak"
   !insertmacro MUI_LANGUAGE "Slovenian"
   !insertmacro MUI_LANGUAGE "Spanish"
+  !insertmacro MUI_LANGUAGE "SpanishInternational"
   !insertmacro MUI_LANGUAGE "Swedish"
+  !insertmacro MUI_LANGUAGE "Tatar"
   !insertmacro MUI_LANGUAGE "Thai"
   !insertmacro MUI_LANGUAGE "TradChinese"
   !insertmacro MUI_LANGUAGE "Turkish"
   !insertmacro MUI_LANGUAGE "Ukrainian"
+  !insertmacro MUI_LANGUAGE "Uzbek"
+  !insertmacro MUI_LANGUAGE "Vietnamese"
   !insertmacro MUI_LANGUAGE "Welsh"
 
 ;--------------------------------
@@ -661,7 +674,7 @@ Section "-Core installation"
   Push "@CPACK_PACKAGE_VENDOR@"
   Call ConditionalAddToRegisty
   Push "UninstallString"
-  Push "$INSTDIR\@CPACK_NSIS_UNINSTALL_NAME@.exe"
+  Push "$\"$INSTDIR\@CPACK_NSIS_UNINSTALL_NAME@.exe$\""
   Call ConditionalAddToRegisty
   Push "NoRepair"
   Push "1"
diff --git a/Modules/Internal/OSRelease/010-TryOldCentOS.cmake b/Modules/Internal/OSRelease/010-TryOldCentOS.cmake
new file mode 100644 (file)
index 0000000..ff35897
--- /dev/null
@@ -0,0 +1,41 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# Author: Alex Turbov
+
+if(NOT EXISTS "${CMAKE_SYSROOT}/etc/centos-release")
+  return()
+endif()
+
+# Get the first string only
+file(
+    STRINGS "${CMAKE_SYSROOT}/etc/centos-release" CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT
+    LIMIT_COUNT 1
+  )
+
+#
+# Example:
+#   CentOS release 6.10 (Final)
+#
+if(CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT MATCHES "CentOS release ([0-9\.]+) .*")
+
+  set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_NAME CentOS)
+  set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_PRETTY_NAME "${CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT}")
+  set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID centos)
+  set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID_LIKE rhel)
+  set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION ${CMAKE_MATCH_1})
+  set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION_ID ${CMAKE_MATCH_1})
+
+  list(
+      APPEND CMAKE_GET_OS_RELEASE_FALLBACK_RESULT
+      CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_NAME
+      CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_PRETTY_NAME
+      CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID
+      CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID_LIKE
+      CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION
+      CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION_ID
+    )
+
+endif()
+
+unset(CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT)
diff --git a/Modules/Internal/OSRelease/020-TryDebianVersion.cmake b/Modules/Internal/OSRelease/020-TryDebianVersion.cmake
new file mode 100644 (file)
index 0000000..8ebe19a
--- /dev/null
@@ -0,0 +1,38 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# Author: Alex Turbov
+
+if(NOT EXISTS "${CMAKE_SYSROOT}/etc/debian_version")
+  return()
+endif()
+
+# Get the first string only
+file(
+    STRINGS "${CMAKE_SYSROOT}/etc/debian_version" CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT
+    LIMIT_COUNT 1
+  )
+
+#
+# Example:
+#   6.0.10          # Old debian
+#   wheezy/sid      # Ubuntu
+#
+if(CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT MATCHES "[0-9]+(\.[0-9]+)*")
+
+  set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_NAME Debian)
+  set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID debian)
+  set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION ${CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT})
+  set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION_ID ${CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT})
+
+  list(
+      APPEND CMAKE_GET_OS_RELEASE_FALLBACK_RESULT
+      CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_NAME
+      CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID
+      CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION
+      CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION_ID
+    )
+
+endif()
+
+unset(CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT)
index 7b67f83..a4e9574 100644 (file)
@@ -52,14 +52,16 @@ if(CMAKE_GENERATOR MATCHES "Visual Studio")
     endif()
     configure_file(${CMAKE_ROOT}/Modules/Platform/Android/VCXProjInspect.vcxproj.in
       ${CMAKE_PLATFORM_INFO_DIR}/VCXProjInspect.vcxproj @ONLY)
+    cmake_host_system_information(RESULT _msbuild QUERY VS_MSBUILD_COMMAND) # undocumented query
     execute_process(
-      COMMAND "${CMAKE_VS_MSBUILD_COMMAND}" "VCXProjInspect.vcxproj"
+      COMMAND "${_msbuild}" "VCXProjInspect.vcxproj"
         "/p:Configuration=Debug" "/p:Platform=${vcx_platform}"
       WORKING_DIRECTORY ${CMAKE_PLATFORM_INFO_DIR}
       OUTPUT_VARIABLE VCXPROJ_INSPECT_OUTPUT
       ERROR_VARIABLE VCXPROJ_INSPECT_OUTPUT
       RESULT_VARIABLE VCXPROJ_INSPECT_RESULT
       )
+    unset(_msbuild)
     if(NOT CMAKE_SYSROOT AND VCXPROJ_INSPECT_OUTPUT MATCHES "CMAKE_SYSROOT=([^%\r\n]+)[\r\n]")
       # Strip VS diagnostic output from the end of the line.
       string(REGEX REPLACE " \\(TaskId:[0-9]*\\)$" "" _sysroot "${CMAKE_MATCH_1}")
index 373be76..1c32018 100644 (file)
@@ -38,6 +38,8 @@ macro(__windows_compiler_clang_gnu lang)
   set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ")
   set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP)
 
+  set(CMAKE_${lang}_LINKER_MANIFEST_FLAG " -Xlinker /MANIFESTINPUT:")
+
   if("${CMAKE_${lang}_SIMULATE_VERSION}" MATCHES "^([0-9]+)\\.([0-9]+)")
     math(EXPR MSVC_VERSION "${CMAKE_MATCH_1}*100 + ${CMAKE_MATCH_2}")
   endif()
@@ -66,10 +68,10 @@ macro(__windows_compiler_clang_gnu lang)
   set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
   set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
   set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
-    "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <OBJECTS> <LINK_LIBRARIES>")
+    "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} -Xlinker /MANIFEST:EMBED -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <OBJECTS> <LINK_LIBRARIES> <MANIFESTS>")
   set(CMAKE_${lang}_CREATE_SHARED_MODULE ${CMAKE_${lang}_CREATE_SHARED_LIBRARY})
   set(CMAKE_${lang}_LINK_EXECUTABLE
-    "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
+    "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Xlinker /MANIFEST:EMBED -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES> <MANIFESTS>")
 
   set(CMAKE_${lang}_CREATE_WIN32_EXE "-Xlinker /subsystem:windows")
   set(CMAKE_${lang}_CREATE_CONSOLE_EXE "-Xlinker /subsystem:console")
index a04882f..51dc146 100644 (file)
@@ -8,6 +8,8 @@ if(__WINDOWS_GNU)
 endif()
 set(__WINDOWS_GNU 1)
 
+set(MINGW 1)
+
 set(CMAKE_IMPORT_LIBRARY_PREFIX "lib")
 set(CMAKE_SHARED_LIBRARY_PREFIX "lib")
 set(CMAKE_SHARED_MODULE_PREFIX  "lib")
@@ -19,16 +21,12 @@ set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll")
 set(CMAKE_SHARED_MODULE_SUFFIX  ".dll")
 set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
 
-if(MSYS OR MINGW)
-  set(CMAKE_EXTRA_LINK_EXTENSIONS ".lib") # MinGW can also link to a MS .lib
-endif()
+set(CMAKE_EXTRA_LINK_EXTENSIONS ".lib") # MinGW can also link to a MS .lib
 
-if(MINGW)
-  set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
-  set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" ".a" ".lib")
-  set(CMAKE_C_STANDARD_LIBRARIES_INIT "-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32")
-  set(CMAKE_CXX_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}")
-endif()
+set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" ".a" ".lib")
+set(CMAKE_C_STANDARD_LIBRARIES_INIT "-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32")
+set(CMAKE_CXX_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}")
 
 set(CMAKE_DL_LIBS "")
 set(CMAKE_LIBRARY_PATH_FLAG "-L")
@@ -48,21 +46,19 @@ endif()
 
 macro(__windows_compiler_gnu lang)
 
-  if(MSYS OR MINGW)
-    # Create archiving rules to support large object file lists for static libraries.
-    set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
-    set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
-    set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
-
-    # Initialize C link type selection flags.  These flags are used when
-    # building a shared library, shared module, or executable that links
-    # to other libraries to select whether to use the static or shared
-    # versions of the libraries.
-    foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
-      set(CMAKE_${type}_LINK_STATIC_${lang}_FLAGS "-Wl,-Bstatic")
-      set(CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS "-Wl,-Bdynamic")
-    endforeach()
-  endif()
+  # Create archiving rules to support large object file lists for static libraries.
+  set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
+  set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+  set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
+
+  # Initialize C link type selection flags.  These flags are used when
+  # building a shared library, shared module, or executable that links
+  # to other libraries to select whether to use the static or shared
+  # versions of the libraries.
+  foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+    set(CMAKE_${type}_LINK_STATIC_${lang}_FLAGS "-Wl,-Bstatic")
+    set(CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS "-Wl,-Bdynamic")
+  endforeach()
 
   # No -fPIC on Windows
   set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "")
index e4d9b93..152b27c 100644 (file)
@@ -1,7 +1,7 @@
 include(Platform/Windows-Intel)
 __windows_compiler_intel(C)
 
-set(CMAKE_DEPFILE_FLAGS_C "-QMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
+set(CMAKE_DEPFILE_FLAGS_C "-QMMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
 set(CMAKE_C_DEPFILE_FORMAT gcc)
 
 if(CMAKE_GENERATOR MATCHES "^Ninja")
index 6adbb6e..ce33ae1 100644 (file)
@@ -2,7 +2,7 @@ include(Platform/Windows-Intel)
 set(_COMPILE_CXX " /TP")
 __windows_compiler_intel(CXX)
 
-set(CMAKE_DEPFILE_FLAGS_CXX "-QMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
+set(CMAKE_DEPFILE_FLAGS_CXX "-QMMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
 set(CMAKE_CXX_DEPFILE_FORMAT gcc)
 
 if(CMAKE_GENERATOR MATCHES "^Ninja")
index 8231e78..b9ea037 100644 (file)
@@ -12,6 +12,6 @@ include(Platform/Windows-MSVC)
 macro(__windows_compiler_intel lang)
   __windows_compiler_msvc(${lang})
 
-  set(CMAKE_DEPFILE_FLAGS_${lang} "-QMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
+  set(CMAKE_DEPFILE_FLAGS_${lang} "-QMMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
   set(CMAKE_${lang}_DEPFILE_FORMAT gcc)
 endmacro()
index b48c33c..9808861 100644 (file)
@@ -192,12 +192,17 @@ ensure generated files will receive the required settings.
   If set to ``TRUE``, implicit dependencies are generated by the ``swig`` tool
   itself. This property is only meaningful for
   :ref:`Makefile <Makefile Generators>`,
-  :ref:`Ninja <Ninja Generators>` and :generator:`Xcode` generators. Default
-  value is ``FALSE``.
+  :ref:`Ninja <Ninja Generators>`, :generator:`Xcode`, and
+  :ref:`Visual Studio <Visual Studio Generators>`
+  (:generator:`Visual Studio 11 2012` and above) generators. Default value is
+  ``FALSE``.
 
   .. versionadded:: 3.21
     Added the support of :generator:`Xcode` generator.
 
+  .. versionadded:: 3.22
+    Added the support of :ref:`Visual Studio Generators`.
+
 ``SWIG_MODULE_NAME``
   Specify the actual import name of the module in the target language.
   This is required if it cannot be scanned automatically from source
@@ -342,8 +347,10 @@ as well as ``SWIG``:
   If set to ``TRUE``, implicit dependencies are generated by the ``swig`` tool
   itself. This variable is only meaningful for
   :ref:`Makefile <Makefile Generators>`,
-  :ref:`Ninja <Ninja Generators>` and :generator:`Xcode` generators. Default
-  value is ``FALSE``.
+  :ref:`Ninja <Ninja Generators>`, :generator:`Xcode`, and
+  :ref:`Visual Studio <Visual Studio Generators>`
+  (:generator:`Visual Studio 11 2012` and above) generators. Default value is
+  ``FALSE``.
 
   Source file property ``USE_SWIG_DEPENDENCIES``, if not defined, will be
   initialized with the value of this variable.
@@ -351,6 +358,9 @@ as well as ``SWIG``:
   .. versionadded:: 3.21
     Added the support of :generator:`Xcode` generator.
 
+  .. versionadded:: 3.22
+    Added the support of :ref:`Visual Studio Generators`.
+
 #]=======================================================================]
 
 cmake_policy(PUSH)
@@ -515,7 +525,7 @@ function(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
   endif()
 
   set (use_swig_dependencies ${SWIG_USE_SWIG_DEPENDENCIES})
-  if (CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode")
+  if (CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode|Visual Studio (1[1-9]|[2-9][0-9])")
     get_property(use_swig_dependencies_set SOURCE "${infile}" PROPERTY USE_SWIG_DEPENDENCIES SET)
     if (use_swig_dependencies_set)
       get_property(use_swig_dependencies SOURCE "${infile}" PROPERTY USE_SWIG_DEPENDENCIES)
@@ -676,7 +686,7 @@ function(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
     ${swig_custom_products}
     ${swig_cleanup_command}
     # Let's create the ${outdir} at execution time, in case dir contains $(OutDir)
-    COMMAND "${CMAKE_COMMAND}" -E make_directory "${workingdir}" "${outdir}" "${outfiledir}"
+    COMMAND "${CMAKE_COMMAND}" -E make_directory ${outdir} ${outfiledir}
     ${swig_timestamp_command}
     COMMAND "${CMAKE_COMMAND}" -E env "SWIG_LIB=${SWIG_DIR}" "${SWIG_EXECUTABLE}"
     "-${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}"
@@ -840,8 +850,9 @@ function(SWIG_ADD_LIBRARY name)
     set(SWIG_SOURCE_FILE_EXTENSIONS ".i")
   endif()
 
-  if (CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode")
-    # For Makefiles and Ninja generators, use SWIG generated dependencies
+  if (CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode|Visual Studio (1[1-9]|[2-9][0-9])")
+    # For Makefiles, Ninja, Xcode and Visual Studio generators,
+    # use SWIG generated dependencies if requested
     if (NOT DEFINED SWIG_USE_SWIG_DEPENDENCIES)
         set (SWIG_USE_SWIG_DEPENDENCIES OFF)
     endif()
index 1b0815e..4ee7643 100644 (file)
@@ -1,6 +1,10 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
+# Not needed for "modern" VTK.
+if (EXISTS "${VTK_SOURCE_DIR}/CMake/vtkModule.cmake")
+  return ()
+endif ()
 
 if(APPLE)
   set(CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}")
index 9a18184..c8498a9 100644 (file)
@@ -10,36 +10,6 @@ if (NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
 endif()
 
 include(CheckIncludeFile)
-# Check if we can build support for ELF parsing.
-if(WIN32)
-  set(HAVE_ELF_H 0)
-elseif(CMAKE_CXX_PLATFORM_ID MATCHES "OpenBSD")
-  CHECK_INCLUDE_FILES("stdint.h;elf_abi.h" HAVE_ELF_H)
-else()
-  CHECK_INCLUDE_FILE("elf.h" HAVE_ELF_H)
-endif()
-if(HAVE_ELF_H)
-  set(CMake_USE_ELF_PARSER 1)
-elseif(HAIKU)
-  # On Haiku, we need to include elf32.h from the private headers
-  set(CMake_HAIKU_INCLUDE_DIRS
-    /boot/system/develop/headers/private/system
-    /boot/system/develop/headers/private/system/arch/x86
-    )
-
-  set(CMAKE_REQUIRED_INCLUDES ${CMake_HAIKU_INCLUDE_DIRS})
-  CHECK_INCLUDE_FILE("elf32.h" HAVE_ELF32_H)
-  unset(CMAKE_REQUIRED_INCLUDES)
-
-  if(HAVE_ELF32_H)
-    set(CMake_USE_ELF_PARSER 1)
-  else()
-    unset(CMake_HAIKU_INCLUDE_DIRS)
-    set(CMake_USE_ELF_PARSER)
-  endif()
-else()
-  set(CMake_USE_ELF_PARSER)
-endif()
 
 if(NOT CMake_DEFAULT_RECURSION_LIMIT)
   if(DEFINED ENV{DASHBOARD_TEST_FROM_CTEST})
@@ -111,11 +81,6 @@ include_directories(
   ${CMake_HAIKU_INCLUDE_DIRS}
   )
 
-# Check if we can build the ELF parser.
-if(CMake_USE_ELF_PARSER)
-  set(ELF_SRCS cmELF.h cmELF.cxx)
-endif()
-
 # Check if we can build the Mach-O parser.
 if(CMake_USE_MACH_PARSER)
   set(MACH_SRCS cmMachO.h cmMachO.cxx)
@@ -245,7 +210,8 @@ set(SRCS
   cmDocumentationSection.cxx
   cmDynamicLoader.cxx
   cmDynamicLoader.h
-  ${ELF_SRCS}
+  cmELF.h
+  cmELF.cxx
   cmExprParserHelper.cxx
   cmExportBuildAndroidMKGenerator.h
   cmExportBuildAndroidMKGenerator.cxx
@@ -415,6 +381,8 @@ set(SRCS
   cmProcessOutput.h
   cmProcessTools.cxx
   cmProcessTools.h
+  cmValue.cxx
+  cmValue.h
   cmProperty.h
   cmPropertyDefinition.cxx
   cmPropertyDefinition.h
@@ -834,7 +802,7 @@ if (WIN32)
 endif ()
 
 # Watcom support
-if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
+if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
   set_property(SOURCE cmake.cxx APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_USE_WMAKE)
   list(APPEND SRCS
     cmGlobalWatcomWMakeGenerator.cxx
@@ -994,6 +962,7 @@ set(CTEST_SRCS cmCTest.cxx
   CTest/cmCTestSubmitHandler.cxx
   CTest/cmCTestTestCommand.cxx
   CTest/cmCTestTestHandler.cxx
+  CTest/cmCTestTestMeasurementXMLParser.cxx
   CTest/cmCTestUpdateCommand.cxx
   CTest/cmCTestUpdateHandler.cxx
   CTest/cmCTestUploadCommand.cxx
index 392f8a9..512f47e 100644 (file)
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
-set(CMake_VERSION_MINOR 21)
-set(CMake_VERSION_PATCH 7)
+set(CMake_VERSION_MINOR 22)
+set(CMake_VERSION_PATCH 0)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
@@ -21,7 +21,7 @@ endif()
 
 if(NOT CMake_VERSION_NO_GIT)
   # If this source was exported by 'git archive', use its commit info.
-  set(git_info [==[97073b1991 CMake 3.21.7]==])
+  set(git_info [==[ff8c3acc0f CMake 3.22.0]==])
 
   # Otherwise, try to identify the current development source version.
   if(NOT git_info MATCHES "^([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]?[0-9a-f]?)[0-9a-f]* "
index 87ebbfe..f6b8a8a 100644 (file)
@@ -21,7 +21,7 @@ cmCPackIFWCommon::cmCPackIFWCommon()
 {
 }
 
-const char* cmCPackIFWCommon::GetOption(const std::string& op) const
+cmValue cmCPackIFWCommon::GetOption(const std::string& op) const
 {
   return this->Generator ? this->Generator->cmCPackGenerator::GetOption(op)
                          : nullptr;
@@ -51,7 +51,7 @@ bool cmCPackIFWCommon::IsVersionLess(const char* version) const
   }
 
   return cmSystemTools::VersionCompare(
-    cmSystemTools::OP_LESS, this->Generator->FrameworkVersion.data(), version);
+    cmSystemTools::OP_LESS, this->Generator->FrameworkVersion, version);
 }
 
 bool cmCPackIFWCommon::IsVersionGreater(const char* version) const
@@ -61,8 +61,7 @@ bool cmCPackIFWCommon::IsVersionGreater(const char* version) const
   }
 
   return cmSystemTools::VersionCompare(
-    cmSystemTools::OP_GREATER, this->Generator->FrameworkVersion.data(),
-    version);
+    cmSystemTools::OP_GREATER, this->Generator->FrameworkVersion, version);
 }
 
 bool cmCPackIFWCommon::IsVersionEqual(const char* version) const
@@ -72,8 +71,7 @@ bool cmCPackIFWCommon::IsVersionEqual(const char* version) const
   }
 
   return cmSystemTools::VersionCompare(
-    cmSystemTools::OP_EQUAL, this->Generator->FrameworkVersion.data(),
-    version);
+    cmSystemTools::OP_EQUAL, this->Generator->FrameworkVersion, version);
 }
 
 void cmCPackIFWCommon::ExpandListArgument(
index 42deda4..f2e6b88 100644 (file)
@@ -7,6 +7,8 @@
 #include <map>
 #include <string>
 
+#include "cmValue.h"
+
 class cmCPackIFWGenerator;
 class cmXMLWriter;
 
@@ -26,7 +28,7 @@ public:
 public:
   // Internal implementation
 
-  const char* GetOption(const std::string& op) const;
+  cmValue GetOption(const std::string& op) const;
   bool IsOn(const std::string& op) const;
   bool IsSetToOff(const std::string& op) const;
   bool IsSetToEmpty(const std::string& op) const;
index 2806c61..b375ba6 100644 (file)
@@ -16,6 +16,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmCPackIFWGenerator::cmCPackIFWGenerator()
 {
@@ -248,9 +249,9 @@ const char* cmCPackIFWGenerator::GetPackagingInstallPrefix()
     tmpPref += "packages/" + this->GetRootPackageName() + "/data";
   }
 
-  this->SetOption("CPACK_IFW_PACKAGING_INSTALL_PREFIX", tmpPref.c_str());
+  this->SetOption("CPACK_IFW_PACKAGING_INSTALL_PREFIX", tmpPref);
 
-  return this->GetOption("CPACK_IFW_PACKAGING_INSTALL_PREFIX");
+  return this->GetOption("CPACK_IFW_PACKAGING_INSTALL_PREFIX")->c_str();
 }
 
 const char* cmCPackIFWGenerator::GetOutputExtension()
@@ -273,11 +274,11 @@ int cmCPackIFWGenerator::InitializeInternal()
 
   // Look 'binarycreator' executable (needs)
 
-  const char* BinCreatorStr = this->GetOption(BinCreatorOpt);
+  cmValue BinCreatorStr = this->GetOption(BinCreatorOpt);
   if (!BinCreatorStr || cmIsNOTFOUND(BinCreatorStr)) {
     this->BinCreator.clear();
   } else {
-    this->BinCreator = BinCreatorStr;
+    this->BinCreator = *BinCreatorStr;
   }
 
   if (this->BinCreator.empty()) {
@@ -290,16 +291,16 @@ int cmCPackIFWGenerator::InitializeInternal()
 
   // Look 'repogen' executable (optional)
 
-  const char* RepoGenStr = this->GetOption(RepoGenOpt);
-  if (!RepoGenStr || cmIsNOTFOUND(RepoGenStr)) {
+  cmValue repoGen = this->GetOption(RepoGenOpt);
+  if (!repoGen || cmIsNOTFOUND(repoGen)) {
     this->RepoGen.clear();
   } else {
-    this->RepoGen = RepoGenStr;
+    this->RepoGen = *repoGen;
   }
 
   // Framework version
-  if (const char* FrameworkVersionSrt = this->GetOption(FrameworkVersionOpt)) {
-    this->FrameworkVersion = FrameworkVersionSrt;
+  if (cmValue frameworkVersion = this->GetOption(FrameworkVersionOpt)) {
+    this->FrameworkVersion = *frameworkVersion;
   } else {
     this->FrameworkVersion = "1.9.9";
   }
@@ -312,14 +313,13 @@ int cmCPackIFWGenerator::InitializeInternal()
 
   // Additional packages dirs
   this->PkgsDirsVector.clear();
-  if (const char* dirs = this->GetOption("CPACK_IFW_PACKAGES_DIRECTORIES")) {
+  if (cmValue dirs = this->GetOption("CPACK_IFW_PACKAGES_DIRECTORIES")) {
     cmExpandList(dirs, this->PkgsDirsVector);
   }
 
   // Additional repositories dirs
   this->RepoDirsVector.clear();
-  if (const char* dirs =
-        this->GetOption("CPACK_IFW_REPOSITORIES_DIRECTORIES")) {
+  if (cmValue dirs = this->GetOption("CPACK_IFW_REPOSITORIES_DIRECTORIES")) {
     cmExpandList(dirs, this->RepoDirsVector);
   }
 
@@ -330,22 +330,22 @@ int cmCPackIFWGenerator::InitializeInternal()
   // Repository
   this->Repository.Generator = this;
   this->Repository.Name = "Unspecified";
-  if (const char* site = this->GetOption("CPACK_DOWNLOAD_SITE")) {
-    this->Repository.Url = site;
+  if (cmValue site = this->GetOption("CPACK_DOWNLOAD_SITE")) {
+    this->Repository.Url = *site;
     this->Installer.RemoteRepositories.push_back(&this->Repository);
   }
 
   // Repositories
-  if (const char* RepoAllStr = this->GetOption("CPACK_IFW_REPOSITORIES_ALL")) {
+  if (cmValue RepoAllStr = this->GetOption("CPACK_IFW_REPOSITORIES_ALL")) {
     std::vector<std::string> RepoAllVector = cmExpandedList(RepoAllStr);
     for (std::string const& r : RepoAllVector) {
       this->GetRepository(r);
     }
   }
 
-  if (const char* ifwDownloadAll = this->GetOption("CPACK_IFW_DOWNLOAD_ALL")) {
+  if (cmValue ifwDownloadAll = this->GetOption("CPACK_IFW_DOWNLOAD_ALL")) {
     this->OnlineOnly = cmIsOn(ifwDownloadAll);
-  } else if (const char* cpackDownloadAll =
+  } else if (cmValue cpackDownloadAll =
                this->GetOption("CPACK_DOWNLOAD_ALL")) {
     this->OnlineOnly = cmIsOn(cpackDownloadAll);
   } else {
@@ -374,9 +374,9 @@ int cmCPackIFWGenerator::InitializeInternal()
   }
 
   // Output extension
-  if (const char* optOutExt =
+  if (cmValue optOutExt =
         this->GetOption("CPACK_IFW_PACKAGE_FILE_EXTENSION")) {
-    this->OutputExtension = optOutExt;
+    this->OutputExtension = *optOutExt;
   } else if (sysName == "Darwin") {
     this->OutputExtension = ".dmg";
   } else {
@@ -508,21 +508,20 @@ std::string cmCPackIFWGenerator::GetRootPackageName()
 {
   // Default value
   std::string name = "root";
-  if (const char* optIFW_PACKAGE_GROUP =
+  if (cmValue optIFW_PACKAGE_GROUP =
         this->GetOption("CPACK_IFW_PACKAGE_GROUP")) {
     // Configure from root group
     cmCPackIFWPackage package;
     package.Generator = this;
     package.ConfigureFromGroup(optIFW_PACKAGE_GROUP);
     name = package.Name;
-  } else if (const char* optIFW_PACKAGE_NAME =
+  } else if (cmValue optIFW_PACKAGE_NAME =
                this->GetOption("CPACK_IFW_PACKAGE_NAME")) {
     // Configure from root package name
-    name = optIFW_PACKAGE_NAME;
-  } else if (const char* optPACKAGE_NAME =
-               this->GetOption("CPACK_PACKAGE_NAME")) {
+    name = *optIFW_PACKAGE_NAME;
+  } else if (cmValue optPACKAGE_NAME = this->GetOption("CPACK_PACKAGE_NAME")) {
     // Configure from package name
-    name = optPACKAGE_NAME;
+    name = *optPACKAGE_NAME;
   }
   return name;
 }
@@ -537,10 +536,10 @@ std::string cmCPackIFWGenerator::GetGroupPackageName(
   if (cmCPackIFWPackage* package = this->GetGroupPackage(group)) {
     return package->Name;
   }
-  const char* option =
+  cmValue option =
     this->GetOption("CPACK_IFW_COMPONENT_GROUP_" +
                     cmsys::SystemTools::UpperCase(group->Name) + "_NAME");
-  name = option ? option : group->Name;
+  name = option ? *option : group->Name;
   if (group->ParentGroup) {
     cmCPackIFWPackage* package = this->GetGroupPackage(group->ParentGroup);
     bool dot = !this->ResolveDuplicateNames;
@@ -563,8 +562,8 @@ std::string cmCPackIFWGenerator::GetComponentPackageName(
   }
   std::string prefix = "CPACK_IFW_COMPONENT_" +
     cmsys::SystemTools::UpperCase(component->Name) + "_";
-  const char* option = this->GetOption(prefix + "NAME");
-  name = option ? option : component->Name;
+  cmValue option = this->GetOption(prefix + "NAME");
+  name = option ? *option : component->Name;
   if (component->Group) {
     cmCPackIFWPackage* package = this->GetGroupPackage(component->Group);
     if ((this->componentPackageMethod ==
index bf8b457..7ee6300 100644 (file)
@@ -14,6 +14,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmXMLParser.h"
 #include "cmXMLWriter.h"
 
@@ -33,61 +34,60 @@ void cmCPackIFWInstaller::printSkippedOptionWarning(
 void cmCPackIFWInstaller::ConfigureFromOptions()
 {
   // Name;
-  if (const char* optIFW_PACKAGE_NAME =
+  if (cmValue optIFW_PACKAGE_NAME =
         this->GetOption("CPACK_IFW_PACKAGE_NAME")) {
-    this->Name = optIFW_PACKAGE_NAME;
-  } else if (const char* optPACKAGE_NAME =
-               this->GetOption("CPACK_PACKAGE_NAME")) {
-    this->Name = optPACKAGE_NAME;
+    this->Name = *optIFW_PACKAGE_NAME;
+  } else if (cmValue optPACKAGE_NAME = this->GetOption("CPACK_PACKAGE_NAME")) {
+    this->Name = *optPACKAGE_NAME;
   } else {
     this->Name = "Your package";
   }
 
   // Title;
-  if (const char* optIFW_PACKAGE_TITLE =
+  if (cmValue optIFW_PACKAGE_TITLE =
         this->GetOption("CPACK_IFW_PACKAGE_TITLE")) {
-    this->Title = optIFW_PACKAGE_TITLE;
-  } else if (const char* optPACKAGE_DESCRIPTION_SUMMARY =
+    this->Title = *optIFW_PACKAGE_TITLE;
+  } else if (cmValue optPACKAGE_DESCRIPTION_SUMMARY =
                this->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY")) {
-    this->Title = optPACKAGE_DESCRIPTION_SUMMARY;
+    this->Title = *optPACKAGE_DESCRIPTION_SUMMARY;
   } else {
     this->Title = "Your package description";
   }
 
   // Version;
-  if (const char* option = this->GetOption("CPACK_PACKAGE_VERSION")) {
-    this->Version = option;
+  if (cmValue option = this->GetOption("CPACK_PACKAGE_VERSION")) {
+    this->Version = *option;
   } else {
     this->Version = "1.0.0";
   }
 
   // Publisher
-  if (const char* optIFW_PACKAGE_PUBLISHER =
+  if (cmValue optIFW_PACKAGE_PUBLISHER =
         this->GetOption("CPACK_IFW_PACKAGE_PUBLISHER")) {
-    this->Publisher = optIFW_PACKAGE_PUBLISHER;
-  } else if (const char* optPACKAGE_VENDOR =
+    this->Publisher = *optIFW_PACKAGE_PUBLISHER;
+  } else if (cmValue optPACKAGE_VENDOR =
                this->GetOption("CPACK_PACKAGE_VENDOR")) {
-    this->Publisher = optPACKAGE_VENDOR;
+    this->Publisher = *optPACKAGE_VENDOR;
   }
 
   // ProductUrl
-  if (const char* option = this->GetOption("CPACK_IFW_PRODUCT_URL")) {
-    this->ProductUrl = option;
+  if (cmValue option = this->GetOption("CPACK_IFW_PRODUCT_URL")) {
+    this->ProductUrl = *option;
   }
 
   // ApplicationIcon
-  if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_ICON")) {
+  if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_ICON")) {
     if (cmSystemTools::FileExists(option)) {
-      this->InstallerApplicationIcon = option;
+      this->InstallerApplicationIcon = *option;
     } else {
       this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_ICON", option);
     }
   }
 
   // WindowIcon
-  if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_WINDOW_ICON")) {
+  if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_WINDOW_ICON")) {
     if (cmSystemTools::FileExists(option)) {
-      this->InstallerWindowIcon = option;
+      this->InstallerWindowIcon = *option;
     } else {
       this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_WINDOW_ICON", option);
     }
@@ -103,45 +103,45 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
   }
 
   // Logo
-  if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_LOGO")) {
+  if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_LOGO")) {
     if (cmSystemTools::FileExists(option)) {
-      this->Logo = option;
+      this->Logo = *option;
     } else {
       this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_LOGO", option);
     }
   }
 
   // Watermark
-  if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_WATERMARK")) {
+  if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_WATERMARK")) {
     if (cmSystemTools::FileExists(option)) {
-      this->Watermark = option;
+      this->Watermark = *option;
     } else {
       this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_WATERMARK", option);
     }
   }
 
   // Banner
-  if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_BANNER")) {
+  if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_BANNER")) {
     if (cmSystemTools::FileExists(option)) {
-      this->Banner = option;
+      this->Banner = *option;
     } else {
       this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_BANNER", option);
     }
   }
 
   // Background
-  if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_BACKGROUND")) {
+  if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_BACKGROUND")) {
     if (cmSystemTools::FileExists(option)) {
-      this->Background = option;
+      this->Background = *option;
     } else {
       this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_BACKGROUND", option);
     }
   }
 
   // WizardStyle
-  if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_WIZARD_STYLE")) {
+  if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_WIZARD_STYLE")) {
     // Setting the user value in any case
-    this->WizardStyle = option;
+    this->WizardStyle = *option;
     // Check known values
     if (this->WizardStyle != "Modern" && this->WizardStyle != "Aero" &&
         this->WizardStyle != "Mac" && this->WizardStyle != "Classic") {
@@ -154,28 +154,28 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
   }
 
   // StyleSheet
-  if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_STYLE_SHEET")) {
+  if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_STYLE_SHEET")) {
     if (cmSystemTools::FileExists(option)) {
-      this->StyleSheet = option;
+      this->StyleSheet = *option;
     } else {
       this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_STYLE_SHEET", option);
     }
   }
 
   // WizardDefaultWidth
-  if (const char* option =
+  if (cmValue option =
         this->GetOption("CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH")) {
-    this->WizardDefaultWidth = option;
+    this->WizardDefaultWidth = *option;
   }
 
   // WizardDefaultHeight
-  if (const char* option =
+  if (cmValue option =
         this->GetOption("CPACK_IFW_PACKAGE_WIZARD_DEFAULT_HEIGHT")) {
-    this->WizardDefaultHeight = option;
+    this->WizardDefaultHeight = *option;
   }
 
   // WizardShowPageList
-  if (const char* option =
+  if (cmValue option =
         this->GetOption("CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST")) {
     if (!this->IsVersionLess("4.0")) {
       if (this->IsSetToOff("CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST")) {
@@ -204,23 +204,23 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
   }
 
   // TitleColor
-  if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_TITLE_COLOR")) {
-    this->TitleColor = option;
+  if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_TITLE_COLOR")) {
+    this->TitleColor = *option;
   }
 
   // Start menu
-  if (const char* optIFW_START_MENU_DIR =
+  if (cmValue optIFW_START_MENU_DIR =
         this->GetOption("CPACK_IFW_PACKAGE_START_MENU_DIRECTORY")) {
-    this->StartMenuDir = optIFW_START_MENU_DIR;
+    this->StartMenuDir = *optIFW_START_MENU_DIR;
   } else {
     this->StartMenuDir = this->Name;
   }
 
   // Default target directory for installation
-  if (const char* optIFW_TARGET_DIRECTORY =
+  if (cmValue optIFW_TARGET_DIRECTORY =
         this->GetOption("CPACK_IFW_TARGET_DIRECTORY")) {
-    this->TargetDir = optIFW_TARGET_DIRECTORY;
-  } else if (const char* optPACKAGE_INSTALL_DIRECTORY =
+    this->TargetDir = *optIFW_TARGET_DIRECTORY;
+  } else if (cmValue optPACKAGE_INSTALL_DIRECTORY =
                this->GetOption("CPACK_PACKAGE_INSTALL_DIRECTORY")) {
     this->TargetDir =
       cmStrCat("@ApplicationsDir@/", optPACKAGE_INSTALL_DIRECTORY);
@@ -229,21 +229,20 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
   }
 
   // Default target directory for installation with administrator rights
-  if (const char* option =
-        this->GetOption("CPACK_IFW_ADMIN_TARGET_DIRECTORY")) {
-    this->AdminTargetDir = option;
+  if (cmValue option = this->GetOption("CPACK_IFW_ADMIN_TARGET_DIRECTORY")) {
+    this->AdminTargetDir = *option;
   }
 
   // Maintenance tool
-  if (const char* optIFW_MAINTENANCE_TOOL =
+  if (cmValue optIFW_MAINTENANCE_TOOL =
         this->GetOption("CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_NAME")) {
-    this->MaintenanceToolName = optIFW_MAINTENANCE_TOOL;
+    this->MaintenanceToolName = *optIFW_MAINTENANCE_TOOL;
   }
 
   // Maintenance tool ini file
-  if (const char* optIFW_MAINTENANCE_TOOL_INI =
+  if (cmValue optIFW_MAINTENANCE_TOOL_INI =
         this->GetOption("CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_INI_FILE")) {
-    this->MaintenanceToolIniFile = optIFW_MAINTENANCE_TOOL_INI;
+    this->MaintenanceToolIniFile = *optIFW_MAINTENANCE_TOOL_INI;
   }
 
   // Allow non-ASCII characters
@@ -265,13 +264,13 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
   }
 
   // Control script
-  if (const char* optIFW_CONTROL_SCRIPT =
+  if (cmValue optIFW_CONTROL_SCRIPT =
         this->GetOption("CPACK_IFW_PACKAGE_CONTROL_SCRIPT")) {
-    this->ControlScript = optIFW_CONTROL_SCRIPT;
+    this->ControlScript = *optIFW_CONTROL_SCRIPT;
   }
 
   // Resources
-  if (const char* optIFW_PACKAGE_RESOURCES =
+  if (cmValue optIFW_PACKAGE_RESOURCES =
         this->GetOption("CPACK_IFW_PACKAGE_RESOURCES")) {
     this->Resources.clear();
     cmExpandList(optIFW_PACKAGE_RESOURCES, this->Resources);
@@ -541,7 +540,7 @@ void cmCPackIFWInstaller::GeneratePackageFiles()
     package.Generator = this->Generator;
     package.Installer = this;
     // Check package group
-    if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_GROUP")) {
+    if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_GROUP")) {
       package.ConfigureFromGroup(option);
       std::string forcedOption = "CPACK_IFW_COMPONENT_GROUP_" +
         cmsys::SystemTools::UpperCase(option) + "_FORCED_INSTALLATION";
index 1429c46..c2109c9 100644 (file)
@@ -18,6 +18,7 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTimestamp.h"
+#include "cmValue.h"
 #include "cmXMLWriter.h"
 
 //---------------------------------------------------------- CompareStruct ---
@@ -124,10 +125,10 @@ std::string cmCPackIFWPackage::GetComponentName(cmCPackComponent* component)
   if (!component) {
     return "";
   }
-  const char* option =
+  cmValue option =
     this->GetOption("CPACK_IFW_COMPONENT_" +
                     cmsys::SystemTools::UpperCase(component->Name) + "_NAME");
-  return option ? option : component->Name;
+  return option ? *option : component->Name;
 }
 
 void cmCPackIFWPackage::DefaultConfiguration()
@@ -159,23 +160,22 @@ int cmCPackIFWPackage::ConfigureFromOptions()
   this->Name = this->Generator->GetRootPackageName();
 
   // Display name
-  if (const char* option = this->GetOption("CPACK_PACKAGE_NAME")) {
-    this->DisplayName[""] = option;
+  if (cmValue option = this->GetOption("CPACK_PACKAGE_NAME")) {
+    this->DisplayName[""] = *option;
   } else {
     this->DisplayName[""] = "Your package";
   }
 
   // Description
-  if (const char* option =
-        this->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY")) {
-    this->Description[""] = option;
+  if (cmValue option = this->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY")) {
+    this->Description[""] = *option;
   } else {
     this->Description[""] = "Your package description";
   }
 
   // Version
-  if (const char* option = this->GetOption("CPACK_PACKAGE_VERSION")) {
-    this->Version = option;
+  if (cmValue option = this->GetOption("CPACK_PACKAGE_VERSION")) {
+    this->Version = *option;
   } else {
     this->Version = "1.0.0";
   }
@@ -204,22 +204,22 @@ int cmCPackIFWPackage::ConfigureFromComponent(cmCPackComponent* component)
   this->Description[""] = component->Description;
 
   // Version
-  if (const char* optVERSION = this->GetOption(prefix + "VERSION")) {
-    this->Version = optVERSION;
-  } else if (const char* optPACKAGE_VERSION =
+  if (cmValue optVERSION = this->GetOption(prefix + "VERSION")) {
+    this->Version = *optVERSION;
+  } else if (cmValue optPACKAGE_VERSION =
                this->GetOption("CPACK_PACKAGE_VERSION")) {
-    this->Version = optPACKAGE_VERSION;
+    this->Version = *optPACKAGE_VERSION;
   } else {
     this->Version = "1.0.0";
   }
 
   // Script
-  if (const char* option = this->GetOption(prefix + "SCRIPT")) {
-    this->Script = option;
+  if (cmValue option = this->GetOption(prefix + "SCRIPT")) {
+    this->Script = *option;
   }
 
   // User interfaces
-  if (const char* option = this->GetOption(prefix + "USER_INTERFACES")) {
+  if (cmValue option = this->GetOption(prefix + "USER_INTERFACES")) {
     this->UserInterfaces.clear();
     cmExpandList(option, this->UserInterfaces);
   }
@@ -232,7 +232,7 @@ int cmCPackIFWPackage::ConfigureFromComponent(cmCPackComponent* component)
   }
 
   // Licenses
-  if (const char* option = this->GetOption(prefix + "LICENSES")) {
+  if (cmValue option = this->GetOption(prefix + "LICENSES")) {
     this->Licenses.clear();
     cmExpandList(option, this->Licenses);
     if (this->Licenses.size() % 2 != 0) {
@@ -246,8 +246,8 @@ int cmCPackIFWPackage::ConfigureFromComponent(cmCPackComponent* component)
   }
 
   // Priority
-  if (const char* option = this->GetOption(prefix + "PRIORITY")) {
-    this->SortingPriority = option;
+  if (cmValue option = this->GetOption(prefix + "PRIORITY")) {
+    this->SortingPriority = *option;
     cmCPackIFWLogger(
       WARNING,
       "The \"PRIORITY\" option is set "
@@ -289,28 +289,28 @@ int cmCPackIFWPackage::ConfigureFromGroup(cmCPackComponentGroup* group)
   this->Description[""] = group->Description;
 
   // Version
-  if (const char* optVERSION = this->GetOption(prefix + "VERSION")) {
-    this->Version = optVERSION;
-  } else if (const char* optPACKAGE_VERSION =
+  if (cmValue optVERSION = this->GetOption(prefix + "VERSION")) {
+    this->Version = *optVERSION;
+  } else if (cmValue optPACKAGE_VERSION =
                this->GetOption("CPACK_PACKAGE_VERSION")) {
-    this->Version = optPACKAGE_VERSION;
+    this->Version = *optPACKAGE_VERSION;
   } else {
     this->Version = "1.0.0";
   }
 
   // Script
-  if (const char* option = this->GetOption(prefix + "SCRIPT")) {
-    this->Script = option;
+  if (cmValue option = this->GetOption(prefix + "SCRIPT")) {
+    this->Script = *option;
   }
 
   // User interfaces
-  if (const char* option = this->GetOption(prefix + "USER_INTERFACES")) {
+  if (cmValue option = this->GetOption(prefix + "USER_INTERFACES")) {
     this->UserInterfaces.clear();
     cmExpandList(option, this->UserInterfaces);
   }
 
   // Licenses
-  if (const char* option = this->GetOption(prefix + "LICENSES")) {
+  if (cmValue option = this->GetOption(prefix + "LICENSES")) {
     this->Licenses.clear();
     cmExpandList(option, this->Licenses);
     if (this->Licenses.size() % 2 != 0) {
@@ -324,8 +324,8 @@ int cmCPackIFWPackage::ConfigureFromGroup(cmCPackComponentGroup* group)
   }
 
   // Priority
-  if (const char* option = this->GetOption(prefix + "PRIORITY")) {
-    this->SortingPriority = option;
+  if (cmValue option = this->GetOption(prefix + "PRIORITY")) {
+    this->SortingPriority = *option;
     cmCPackIFWLogger(
       WARNING,
       "The \"PRIORITY\" option is set "
@@ -346,14 +346,14 @@ int cmCPackIFWPackage::ConfigureFromGroup(const std::string& groupName)
   std::string prefix =
     "CPACK_COMPONENT_GROUP_" + cmsys::SystemTools::UpperCase(groupName) + "_";
 
-  if (const char* option = this->GetOption(prefix + "DISPLAY_NAME")) {
-    group.DisplayName = option;
+  if (cmValue option = this->GetOption(prefix + "DISPLAY_NAME")) {
+    group.DisplayName = *option;
   } else {
     group.DisplayName = group.Name;
   }
 
-  if (const char* option = this->GetOption(prefix + "DESCRIPTION")) {
-    group.Description = option;
+  if (cmValue option = this->GetOption(prefix + "DESCRIPTION")) {
+    group.Description = *option;
   }
   group.IsBold = this->IsOn(prefix + "BOLD_TITLE");
   group.IsExpandedByDefault = this->IsOn(prefix + "EXPANDED");
@@ -381,7 +381,7 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
   option = prefix + "DISPLAY_NAME";
   if (this->IsSetToEmpty(option)) {
     this->DisplayName.clear();
-  } else if (const char* value = this->GetOption(option)) {
+  } else if (cmValue value = this->GetOption(option)) {
     cmCPackIFWPackage::ExpandListArgument(value, this->DisplayName);
   }
 
@@ -389,7 +389,7 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
   option = prefix + "DESCRIPTION";
   if (this->IsSetToEmpty(option)) {
     this->Description.clear();
-  } else if (const char* value = this->GetOption(option)) {
+  } else if (cmValue value = this->GetOption(option)) {
     cmCPackIFWPackage::ExpandListArgument(value, this->Description);
   }
 
@@ -397,31 +397,31 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
   option = prefix + "RELEASE_DATE";
   if (this->IsSetToEmpty(option)) {
     this->ReleaseDate.clear();
-  } else if (const char* value = this->GetOption(option)) {
-    this->ReleaseDate = value;
+  } else if (cmValue value = this->GetOption(option)) {
+    this->ReleaseDate = *value;
   }
 
   // Sorting priority
   option = prefix + "SORTING_PRIORITY";
   if (this->IsSetToEmpty(option)) {
     this->SortingPriority.clear();
-  } else if (const char* value = this->GetOption(option)) {
-    this->SortingPriority = value;
+  } else if (cmValue value = this->GetOption(option)) {
+    this->SortingPriority = *value;
   }
 
   // Update text
   option = prefix + "UPDATE_TEXT";
   if (this->IsSetToEmpty(option)) {
     this->UpdateText.clear();
-  } else if (const char* value = this->GetOption(option)) {
-    this->UpdateText = value;
+  } else if (cmValue value = this->GetOption(option)) {
+    this->UpdateText = *value;
   }
 
   // Translations
   option = prefix + "TRANSLATIONS";
   if (this->IsSetToEmpty(option)) {
     this->Translations.clear();
-  } else if (const char* value = this->GetOption(option)) {
+  } else if (cmValue value = this->GetOption(option)) {
     this->Translations.clear();
     cmExpandList(value, this->Translations);
   }
@@ -429,11 +429,11 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
   // QtIFW dependencies
   std::vector<std::string> deps;
   option = prefix + "DEPENDS";
-  if (const char* value = this->GetOption(option)) {
+  if (cmValue value = this->GetOption(option)) {
     cmExpandList(value, deps);
   }
   option = prefix + "DEPENDENCIES";
-  if (const char* value = this->GetOption(option)) {
+  if (cmValue value = this->GetOption(option)) {
     cmExpandList(value, deps);
   }
   for (std::string const& d : deps) {
@@ -454,7 +454,7 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
   option = prefix + "AUTO_DEPEND_ON";
   if (this->IsSetToEmpty(option)) {
     this->AlienAutoDependOn.clear();
-  } else if (const char* value = this->GetOption(option)) {
+  } else if (cmValue value = this->GetOption(option)) {
     std::vector<std::string> depsOn = cmExpandedList(value);
     for (std::string const& d : depsOn) {
       DependenceStruct dep(d);
@@ -483,7 +483,7 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
   option = prefix + "DEFAULT";
   if (this->IsSetToEmpty(option)) {
     this->Default.clear();
-  } else if (const char* value = this->GetOption(option)) {
+  } else if (cmValue value = this->GetOption(option)) {
     std::string lowerValue = cmsys::SystemTools::LowerCase(value);
     if (lowerValue == "true") {
       this->Default = "true";
@@ -492,7 +492,7 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
     } else if (lowerValue == "script") {
       this->Default = "script";
     } else {
-      this->Default = value;
+      this->Default = *value;
     }
   }
 
@@ -510,7 +510,7 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
   option = prefix + "REPLACES";
   if (this->IsSetToEmpty(option)) {
     this->Replaces.clear();
-  } else if (const char* value = this->GetOption(option)) {
+  } else if (cmValue value = this->GetOption(option)) {
     this->Replaces.clear();
     cmExpandList(value, this->Replaces);
   }
index 7ec2256..f25d2d2 100644 (file)
@@ -7,6 +7,7 @@
 #include "cmCPackIFWGenerator.h"
 #include "cmGeneratedFileStream.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmXMLParser.h"
 #include "cmXMLWriter.h"
 
@@ -55,22 +56,22 @@ bool cmCPackIFWRepository::ConfigureFromOptions()
   }
 
   // Url
-  if (const char* url = this->GetOption(prefix + "URL")) {
-    this->Url = url;
+  if (cmValue url = this->GetOption(prefix + "URL")) {
+    this->Url = *url;
   } else {
     this->Url.clear();
   }
 
   // Old url
-  if (const char* oldUrl = this->GetOption(prefix + "OLD_URL")) {
-    this->OldUrl = oldUrl;
+  if (cmValue oldUrl = this->GetOption(prefix + "OLD_URL")) {
+    this->OldUrl = *oldUrl;
   } else {
     this->OldUrl.clear();
   }
 
   // New url
-  if (const char* newUrl = this->GetOption(prefix + "NEW_URL")) {
-    this->NewUrl = newUrl;
+  if (cmValue newUrl = this->GetOption(prefix + "NEW_URL")) {
+    this->NewUrl = *newUrl;
   } else {
     this->NewUrl.clear();
   }
@@ -83,22 +84,22 @@ bool cmCPackIFWRepository::ConfigureFromOptions()
   }
 
   // Username
-  if (const char* username = this->GetOption(prefix + "USERNAME")) {
-    this->Username = username;
+  if (cmValue username = this->GetOption(prefix + "USERNAME")) {
+    this->Username = *username;
   } else {
     this->Username.clear();
   }
 
   // Password
-  if (const char* password = this->GetOption(prefix + "PASSWORD")) {
-    this->Password = password;
+  if (cmValue password = this->GetOption(prefix + "PASSWORD")) {
+    this->Password = *password;
   } else {
     this->Password.clear();
   }
 
   // DisplayName
-  if (const char* displayName = this->GetOption(prefix + "DISPLAY_NAME")) {
-    this->DisplayName = displayName;
+  if (cmValue displayName = this->GetOption(prefix + "DISPLAY_NAME")) {
+    this->DisplayName = *displayName;
   } else {
     this->DisplayName.clear();
   }
index bdaf779..b7140ab 100644 (file)
@@ -118,5 +118,5 @@ int main(int argc, char* argv[])
 
   cmsysProcess_Delete(cp);
 
-  return 0;
+  return !result;
 }
index 8b3644f..d03239b 100644 (file)
@@ -21,6 +21,7 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmUuid.h"
+#include "cmValue.h"
 #include "cmWIXDirectoriesSourceWriter.h"
 #include "cmWIXFeaturesSourceWriter.h"
 #include "cmWIXFilesSourceWriter.h"
@@ -125,7 +126,7 @@ bool cmCPackWIXGenerator::RunLightCommand(std::string const& objectFiles)
     command << " -ext " << QuotePath(ext);
   }
 
-  const char* const cultures = GetOption("CPACK_WIX_CULTURES");
+  cmValue const cultures = GetOption("CPACK_WIX_CULTURES");
   if (cultures) {
     command << " -cultures:" << cultures;
   }
@@ -156,18 +157,18 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration()
     return false;
   }
 
-  if (GetOption("CPACK_WIX_PRODUCT_GUID") == 0) {
+  if (!GetOption("CPACK_WIX_PRODUCT_GUID")) {
     std::string guid = GenerateGUID();
-    SetOption("CPACK_WIX_PRODUCT_GUID", guid.c_str());
+    SetOption("CPACK_WIX_PRODUCT_GUID", guid);
 
     cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                   "CPACK_WIX_PRODUCT_GUID implicitly set to " << guid << " . "
                                                               << std::endl);
   }
 
-  if (GetOption("CPACK_WIX_UPGRADE_GUID") == 0) {
+  if (!GetOption("CPACK_WIX_UPGRADE_GUID")) {
     std::string guid = GenerateGUID();
-    SetOption("CPACK_WIX_UPGRADE_GUID", guid.c_str());
+    SetOption("CPACK_WIX_UPGRADE_GUID", guid);
 
     cmCPackLogger(cmCPackLog::LOG_WARNING,
                   "CPACK_WIX_UPGRADE_GUID implicitly set to "
@@ -182,36 +183,36 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration()
     return false;
   }
 
-  if (GetOption("CPACK_WIX_LICENSE_RTF") == 0) {
+  if (!GetOption("CPACK_WIX_LICENSE_RTF")) {
     std::string licenseFilename = this->CPackTopLevel + "/License.rtf";
-    SetOption("CPACK_WIX_LICENSE_RTF", licenseFilename.c_str());
+    SetOption("CPACK_WIX_LICENSE_RTF", licenseFilename);
 
     if (!CreateLicenseFile()) {
       return false;
     }
   }
 
-  if (GetOption("CPACK_PACKAGE_VENDOR") == 0) {
+  if (!GetOption("CPACK_PACKAGE_VENDOR")) {
     std::string defaultVendor = "Humanity";
-    SetOption("CPACK_PACKAGE_VENDOR", defaultVendor.c_str());
+    SetOption("CPACK_PACKAGE_VENDOR", defaultVendor);
 
     cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                   "CPACK_PACKAGE_VENDOR implicitly set to "
                     << defaultVendor << " . " << std::endl);
   }
 
-  if (GetOption("CPACK_WIX_UI_REF") == 0) {
+  if (!GetOption("CPACK_WIX_UI_REF")) {
     std::string defaultRef = "WixUI_InstallDir";
 
     if (!this->Components.empty()) {
       defaultRef = "WixUI_FeatureTree";
     }
 
-    SetOption("CPACK_WIX_UI_REF", defaultRef.c_str());
+    SetOption("CPACK_WIX_UI_REF", defaultRef);
   }
 
-  const char* packageContact = GetOption("CPACK_PACKAGE_CONTACT");
-  if (packageContact != 0 && GetOption("CPACK_WIX_PROPERTY_ARPCONTACT") == 0) {
+  cmValue packageContact = GetOption("CPACK_PACKAGE_CONTACT");
+  if (packageContact && !GetOption("CPACK_WIX_PROPERTY_ARPCONTACT")) {
     SetOption("CPACK_WIX_PROPERTY_ARPCONTACT", packageContact);
   }
 
@@ -223,7 +224,7 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration()
   CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", this->LightExtensions);
   CollectXmlNamespaces("CPACK_WIX_CUSTOM_XMLNS", this->CustomXmlNamespaces);
 
-  const char* patchFilePath = GetOption("CPACK_WIX_PATCH_FILE");
+  cmValue patchFilePath = GetOption("CPACK_WIX_PATCH_FILE");
   if (patchFilePath) {
     std::vector<std::string> patchFilePaths = cmExpandedList(patchFilePath);
 
@@ -295,7 +296,7 @@ bool cmCPackWIXGenerator::PackageFilesImpl()
 
 void cmCPackWIXGenerator::AppendUserSuppliedExtraSources()
 {
-  const char* cpackWixExtraSources = GetOption("CPACK_WIX_EXTRA_SOURCES");
+  cmValue cpackWixExtraSources = GetOption("CPACK_WIX_EXTRA_SOURCES");
   if (!cpackWixExtraSources)
     return;
 
@@ -304,7 +305,7 @@ void cmCPackWIXGenerator::AppendUserSuppliedExtraSources()
 
 void cmCPackWIXGenerator::AppendUserSuppliedExtraObjects(std::ostream& stream)
 {
-  const char* cpackWixExtraObjects = GetOption("CPACK_WIX_EXTRA_OBJECTS");
+  cmValue cpackWixExtraObjects = GetOption("CPACK_WIX_EXTRA_OBJECTS");
   if (!cpackWixExtraObjects)
     return;
 
@@ -355,7 +356,7 @@ void cmCPackWIXGenerator::CreateWiXPropertiesIncludeFile()
   for (std::string const& name : options) {
     if (cmHasPrefix(name, prefix)) {
       std::string id = name.substr(prefix.length());
-      std::string value = GetOption(name.c_str());
+      std::string value = GetOption(name);
 
       includeFile.BeginElement("Property");
       includeFile.AddAttribute("Id", id);
@@ -364,7 +365,7 @@ void cmCPackWIXGenerator::CreateWiXPropertiesIncludeFile()
     }
   }
 
-  if (GetOption("CPACK_WIX_PROPERTY_ARPINSTALLLOCATION") == 0) {
+  if (!GetOption("CPACK_WIX_PROPERTY_ARPINSTALLLOCATION")) {
     includeFile.BeginElement("Property");
     includeFile.AddAttribute("Id", "INSTALL_ROOT");
     includeFile.AddAttribute("Secure", "yes");
@@ -405,7 +406,7 @@ void cmCPackWIXGenerator::CopyDefinition(cmWIXSourceWriter& source,
                                          std::string const& name,
                                          DefinitionType type)
 {
-  const char* value = GetOption(name.c_str());
+  cmValue value = GetOption(name);
   if (value) {
     if (type == DefinitionType::PATH) {
       AddDefinition(source, name, CMakeToWixPath(value));
@@ -485,17 +486,17 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
   }
 
   std::string featureTitle = cpackPackageName;
-  if (const char* title = GetOption("CPACK_WIX_ROOT_FEATURE_TITLE")) {
-    featureTitle = title;
+  if (cmValue title = GetOption("CPACK_WIX_ROOT_FEATURE_TITLE")) {
+    featureTitle = *title;
   }
   featureDefinitions.AddAttribute("Title", featureTitle);
-  if (const char* desc = GetOption("CPACK_WIX_ROOT_FEATURE_DESCRIPTION")) {
+  if (cmValue desc = GetOption("CPACK_WIX_ROOT_FEATURE_DESCRIPTION")) {
     featureDefinitions.AddAttribute("Description", desc);
   }
   featureDefinitions.AddAttribute("Level", "1");
   this->Patch->ApplyFragment("#PRODUCTFEATURE", featureDefinitions);
 
-  const char* package = GetOption("CPACK_WIX_CMAKE_PACKAGE_REGISTRY");
+  cmValue package = GetOption("CPACK_WIX_CMAKE_PACKAGE_REGISTRY");
   if (package) {
     featureDefinitions.CreateCMakePackageRegistryEntry(
       package, GetOption("CPACK_WIX_UPGRADE_GUID"));
@@ -540,10 +541,9 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
   }
 
   bool emitUninstallShortcut = true;
-  const char* cpackWixProgramMenuFolder =
+  cmValue cpackWixProgramMenuFolder =
     GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER");
-  if (cpackWixProgramMenuFolder &&
-      cm::string_view(cpackWixProgramMenuFolder) == ".") {
+  if (cpackWixProgramMenuFolder && cpackWixProgramMenuFolder == ".") {
     emitUninstallShortcut = false;
   } else if (emittedShortcutTypes.find(cmWIXShortcuts::START_MENU) ==
              emittedShortcutTypes.end()) {
@@ -595,9 +595,9 @@ std::string cmCPackWIXGenerator::GetRootFolderId() const
 
   std::string result = "ProgramFiles<64>Folder";
 
-  const char* rootFolderId = GetOption("CPACK_WIX_ROOT_FOLDER_ID");
+  cmValue rootFolderId = GetOption("CPACK_WIX_ROOT_FOLDER_ID");
   if (rootFolderId) {
-    result = rootFolderId;
+    result = *rootFolderId;
   }
 
   if (GetArchitecture() == "x86") {
@@ -612,8 +612,8 @@ std::string cmCPackWIXGenerator::GetRootFolderId() const
 bool cmCPackWIXGenerator::GenerateMainSourceFileFromTemplate()
 {
   std::string wixTemplate = FindTemplate("WIX.template.in");
-  if (GetOption("CPACK_WIX_TEMPLATE") != 0) {
-    wixTemplate = GetOption("CPACK_WIX_TEMPLATE");
+  if (cmValue wixtpl = GetOption("CPACK_WIX_TEMPLATE")) {
+    wixTemplate = *wixtpl;
   }
 
   if (wixTemplate.empty()) {
@@ -669,7 +669,7 @@ bool cmCPackWIXGenerator::AddComponentsToFeature(
   featureDefinitions.AddAttribute("Id", featureId);
 
   std::vector<std::string> cpackPackageExecutablesList;
-  const char* cpackPackageExecutables = GetOption("CPACK_PACKAGE_EXECUTABLES");
+  cmValue cpackPackageExecutables = GetOption("CPACK_PACKAGE_EXECUTABLES");
   if (cpackPackageExecutables) {
     cmExpandList(cpackPackageExecutables, cpackPackageExecutablesList);
     if (cpackPackageExecutablesList.size() % 2 != 0) {
@@ -683,8 +683,7 @@ bool cmCPackWIXGenerator::AddComponentsToFeature(
   }
 
   std::vector<std::string> cpackPackageDesktopLinksList;
-  const char* cpackPackageDesktopLinks =
-    GetOption("CPACK_CREATE_DESKTOP_LINKS");
+  cmValue cpackPackageDesktopLinks = GetOption("CPACK_CREATE_DESKTOP_LINKS");
   if (cpackPackageDesktopLinks) {
     cmExpandList(cpackPackageDesktopLinks, cpackPackageDesktopLinksList);
   }
@@ -743,10 +742,9 @@ bool cmCPackWIXGenerator::CreateShortcutsOfSpecificType(
   std::string directoryId;
   switch (type) {
     case cmWIXShortcuts::START_MENU: {
-      const char* cpackWixProgramMenuFolder =
+      cmValue cpackWixProgramMenuFolder =
         GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER");
-      if (cpackWixProgramMenuFolder &&
-          cm::string_view(cpackWixProgramMenuFolder) == ".") {
+      if (cpackWixProgramMenuFolder && cpackWixProgramMenuFolder == ".") {
         directoryId = "ProgramMenuFolder";
       } else {
         directoryId = "PROGRAM_MENU_FOLDER";
@@ -805,10 +803,9 @@ bool cmCPackWIXGenerator::CreateShortcutsOfSpecificType(
                           fileDefinitions);
 
   if (type == cmWIXShortcuts::START_MENU) {
-    const char* cpackWixProgramMenuFolder =
+    cmValue cpackWixProgramMenuFolder =
       GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER");
-    if (cpackWixProgramMenuFolder &&
-        cm::string_view(cpackWixProgramMenuFolder) != ".") {
+    if (cpackWixProgramMenuFolder && cpackWixProgramMenuFolder != ".") {
       fileDefinitions.EmitRemoveFolder("CM_REMOVE_PROGRAM_MENU_FOLDER" +
                                        idSuffix);
     }
@@ -973,9 +970,9 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitions(
 bool cmCPackWIXGenerator::RequireOption(std::string const& name,
                                         std::string& value) const
 {
-  const char* tmp = GetOption(name.c_str());
+  cmValue tmp = GetOption(name);
   if (tmp) {
-    value = tmp;
+    value = *tmp;
 
     return true;
   } else {
@@ -1146,7 +1143,7 @@ bool cmCPackWIXGenerator::IsLegalIdCharacter(char c)
 void cmCPackWIXGenerator::CollectExtensions(std::string const& variableName,
                                             extension_set_t& extensions)
 {
-  const char* variableContent = GetOption(variableName.c_str());
+  cmValue variableContent = GetOption(variableName);
   if (!variableContent)
     return;
 
@@ -1157,7 +1154,7 @@ void cmCPackWIXGenerator::CollectExtensions(std::string const& variableName,
 void cmCPackWIXGenerator::CollectXmlNamespaces(std::string const& variableName,
                                                xmlns_map_t& namespaces)
 {
-  const char* variableContent = GetOption(variableName.c_str());
+  cmValue variableContent = GetOption(variableName);
   if (!variableContent) {
     return;
   }
@@ -1180,13 +1177,13 @@ void cmCPackWIXGenerator::CollectXmlNamespaces(std::string const& variableName,
     oss << " xmlns:" << ns.first << "=\""
         << cmWIXSourceWriter::EscapeAttributeValue(ns.second) << '"';
   }
-  SetOption("CPACK_WIX_CUSTOM_XMLNS_EXPANDED", oss.str().c_str());
+  SetOption("CPACK_WIX_CUSTOM_XMLNS_EXPANDED", oss.str());
 }
 
 void cmCPackWIXGenerator::AddCustomFlags(std::string const& variableName,
                                          std::ostream& stream)
 {
-  const char* variableContent = GetOption(variableName.c_str());
+  cmValue variableContent = GetOption(variableName);
   if (!variableContent)
     return;
 
index d9234e6..56e8463 100644 (file)
@@ -2,7 +2,6 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCPackArchiveGenerator.h"
 
-#include <cstdlib>
 #include <cstring>
 #include <map>
 #include <ostream>
@@ -15,6 +14,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmWorkingDirectory.h"
 
 cmCPackGenerator* cmCPackArchiveGenerator::Create7ZGenerator()
@@ -77,7 +77,7 @@ std::string cmCPackArchiveGenerator::GetArchiveComponentFileName(
 
   if (this->IsSet("CPACK_ARCHIVE_" + componentUpper + "_FILE_NAME")) {
     packageFileName +=
-      this->GetOption("CPACK_ARCHIVE_" + componentUpper + "_FILE_NAME");
+      *this->GetOption("CPACK_ARCHIVE_" + componentUpper + "_FILE_NAME");
   } else if (this->IsSet("CPACK_ARCHIVE_FILE_NAME")) {
     packageFileName += this->GetComponentPackageFileName(
       this->GetOption("CPACK_ARCHIVE_FILE_NAME"), component, isGroupName);
@@ -118,11 +118,11 @@ int cmCPackArchiveGenerator::addOneComponentToArchive(
   if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
     filePrefix = cmStrCat(this->GetOption("CPACK_PACKAGE_FILE_NAME"), '/');
   }
-  const char* installPrefix =
-    this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
-  if (installPrefix && installPrefix[0] == '/' && installPrefix[1] != 0) {
+  cmValue installPrefix = this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
+  if (installPrefix && installPrefix->size() > 1 &&
+      (*installPrefix)[0] == '/') {
     // add to file prefix and remove the leading '/'
-    filePrefix += installPrefix + 1;
+    filePrefix += installPrefix->substr(1);
     filePrefix += "/";
   }
   for (std::string const& file : component->Files) {
@@ -257,9 +257,9 @@ int cmCPackArchiveGenerator::PackageComponentsAllInOne()
   this->packageFileNames[0] += "/";
 
   if (this->IsSet("CPACK_ARCHIVE_FILE_NAME")) {
-    this->packageFileNames[0] += this->GetOption("CPACK_ARCHIVE_FILE_NAME");
+    this->packageFileNames[0] += *this->GetOption("CPACK_ARCHIVE_FILE_NAME");
   } else {
-    this->packageFileNames[0] += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+    this->packageFileNames[0] += *this->GetOption("CPACK_PACKAGE_FILE_NAME");
   }
 
   this->packageFileNames[0] += this->GetOutputExtension();
@@ -345,9 +345,9 @@ int cmCPackArchiveGenerator::GetThreadCount() const
 
   // CPACK_ARCHIVE_THREADS overrides CPACK_THREADS
   if (this->IsSet("CPACK_ARCHIVE_THREADS")) {
-    threads = std::atoi(this->GetOption("CPACK_ARCHIVE_THREADS"));
+    threads = std::stoi(this->GetOption("CPACK_ARCHIVE_THREADS"));
   } else if (this->IsSet("CPACK_THREADS")) {
-    threads = std::atoi(this->GetOption("CPACK_THREADS"));
+    threads = std::stoi(this->GetOption("CPACK_THREADS"));
   }
 
   return threads;
index 4d5f43f..b3d425a 100644 (file)
@@ -8,6 +8,7 @@
 #include "cmCPackLog.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmCPackBundleGenerator::cmCPackBundleGenerator() = default;
 
@@ -15,8 +16,8 @@ cmCPackBundleGenerator::~cmCPackBundleGenerator() = default;
 
 int cmCPackBundleGenerator::InitializeInternal()
 {
-  const char* name = this->GetOption("CPACK_BUNDLE_NAME");
-  if (nullptr == name) {
+  cmValue name = this->GetOption("CPACK_BUNDLE_NAME");
+  if (!name) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "CPACK_BUNDLE_NAME must be set to use the Bundle generator."
                     << std::endl);
@@ -33,7 +34,7 @@ int cmCPackBundleGenerator::InitializeInternal()
                     "Cannot locate codesign command" << std::endl);
       return 0;
     }
-    this->SetOptionIfNotSet("CPACK_COMMAND_CODESIGN", codesign_path.c_str());
+    this->SetOptionIfNotSet("CPACK_COMMAND_CODESIGN", codesign_path);
   }
 
   return this->Superclass::InitializeInternal();
@@ -51,30 +52,24 @@ int cmCPackBundleGenerator::ConstructBundle()
 {
 
   // Get required arguments ...
-  const std::string cpack_bundle_name = this->GetOption("CPACK_BUNDLE_NAME")
-    ? this->GetOption("CPACK_BUNDLE_NAME")
-    : "";
-  if (cpack_bundle_name.empty()) {
+  cmValue cpack_bundle_name = this->GetOption("CPACK_BUNDLE_NAME");
+  if (cpack_bundle_name->empty()) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "CPACK_BUNDLE_NAME must be set." << std::endl);
 
     return 0;
   }
 
-  const std::string cpack_bundle_plist = this->GetOption("CPACK_BUNDLE_PLIST")
-    ? this->GetOption("CPACK_BUNDLE_PLIST")
-    : "";
-  if (cpack_bundle_plist.empty()) {
+  cmValue cpack_bundle_plist = this->GetOption("CPACK_BUNDLE_PLIST");
+  if (cpack_bundle_plist->empty()) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "CPACK_BUNDLE_PLIST must be set." << std::endl);
 
     return 0;
   }
 
-  const std::string cpack_bundle_icon = this->GetOption("CPACK_BUNDLE_ICON")
-    ? this->GetOption("CPACK_BUNDLE_ICON")
-    : "";
-  if (cpack_bundle_icon.empty()) {
+  cmValue cpack_bundle_icon = this->GetOption("CPACK_BUNDLE_ICON");
+  if (cpack_bundle_icon->empty()) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "CPACK_BUNDLE_ICON must be set." << std::endl);
 
@@ -82,10 +77,8 @@ int cmCPackBundleGenerator::ConstructBundle()
   }
 
   // Get optional arguments ...
-  const std::string cpack_bundle_startup_command =
-    this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND")
-    ? this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND")
-    : "";
+  cmValue cpack_bundle_startup_command =
+    this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND");
 
   // The staging directory contains everything that will end-up inside the
   // final disk image ...
@@ -138,7 +131,7 @@ int cmCPackBundleGenerator::ConstructBundle()
 
   // Optionally a user-provided startup command (could be an
   // executable or a script) ...
-  if (!cpack_bundle_startup_command.empty()) {
+  if (!cpack_bundle_startup_command->empty()) {
     std::ostringstream command_source;
     command_source << cpack_bundle_startup_command;
 
@@ -180,13 +173,11 @@ bool cmCPackBundleGenerator::SupportsComponentInstallation() const
 
 int cmCPackBundleGenerator::SignBundle(const std::string& src_dir)
 {
-  const std::string cpack_apple_cert_app =
-    this->GetOption("CPACK_BUNDLE_APPLE_CERT_APP")
-    ? this->GetOption("CPACK_BUNDLE_APPLE_CERT_APP")
-    : "";
+  cmValue cpack_apple_cert_app =
+    this->GetOption("CPACK_BUNDLE_APPLE_CERT_APP");
 
   // codesign the application.
-  if (!cpack_apple_cert_app.empty()) {
+  if (!cpack_apple_cert_app->empty()) {
     std::string output;
     std::string bundle_path;
     bundle_path =
@@ -195,13 +186,10 @@ int cmCPackBundleGenerator::SignBundle(const std::string& src_dir)
     // A list of additional files to sign, ie. frameworks and plugins.
     const std::string sign_parameter =
       this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_PARAMETER")
-      ? this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_PARAMETER")
+      ? *this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_PARAMETER")
       : "--deep -f";
 
-    const std::string sign_files =
-      this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_FILES")
-      ? this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_FILES")
-      : "";
+    cmValue sign_files = this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_FILES");
 
     std::vector<std::string> relFiles = cmExpandedList(sign_files);
 
index b5abd5a..484db00 100644 (file)
@@ -9,6 +9,7 @@
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 cmCPackCygwinBinaryGenerator::cmCPackCygwinBinaryGenerator()
@@ -59,14 +60,15 @@ int cmCPackCygwinBinaryGenerator::PackageFiles()
 const char* cmCPackCygwinBinaryGenerator::GetOutputExtension()
 {
   this->OutputExtension = "-";
-  const char* patchNumber = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
+  cmValue patchNumber = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
   if (!patchNumber) {
-    patchNumber = "1";
+    this->OutputExtension += "1";
     cmCPackLogger(cmCPackLog::LOG_WARNING,
                   "CPACK_CYGWIN_PATCH_NUMBER not specified using 1"
                     << std::endl);
+  } else {
+    this->OutputExtension += patchNumber;
   }
-  this->OutputExtension += patchNumber;
   this->OutputExtension += ".tar.bz2";
   return this->OutputExtension.c_str();
 }
index 64a88eb..59df380 100644 (file)
@@ -9,6 +9,7 @@
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 // Includes needed for implementation of RenameFile.  This is not in
@@ -94,14 +95,15 @@ int cmCPackCygwinSourceGenerator::PackageFiles()
   }
   std::string outerTarFile =
     cmStrCat(this->GetOption("CPACK_TEMPORARY_DIRECTORY"), '-');
-  const char* patch = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
+  cmValue patch = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
   if (!patch) {
     cmCPackLogger(cmCPackLog::LOG_WARNING,
                   "CPACK_CYGWIN_PATCH_NUMBER"
                     << " not specified, defaulting to 1\n");
-    patch = "1";
+    outerTarFile += "1";
+  } else {
+    outerTarFile += patch;
   }
-  outerTarFile += patch;
   outerTarFile += "-src.tar.bz2";
   std::string tmpDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
   std::string buildScript =
@@ -145,14 +147,15 @@ const char* cmCPackCygwinSourceGenerator::GetPackagingInstallPrefix()
 const char* cmCPackCygwinSourceGenerator::GetOutputExtension()
 {
   this->OutputExtension = "-";
-  const char* patch = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
+  cmValue patch = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
   if (!patch) {
     cmCPackLogger(cmCPackLog::LOG_WARNING,
                   "CPACK_CYGWIN_PATCH_NUMBER"
                     << " not specified, defaulting to 1\n");
-    patch = "1";
+    this->OutputExtension += "1";
+  } else {
+    this->OutputExtension += patch;
   }
-  this->OutputExtension += patch;
   this->OutputExtension += "-src.tar.bz2";
   return this->OutputExtension.c_str();
 }
index a1ebbdf..d7aa287 100644 (file)
@@ -2,11 +2,12 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCPackDebGenerator.h"
 
-#include <cstdlib>
+#include <algorithm>
 #include <cstring>
 #include <map>
 #include <ostream>
 #include <set>
+#include <stdexcept>
 #include <utility>
 
 #include "cmsys/Glob.hxx"
@@ -21,6 +22,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 namespace {
 
@@ -29,12 +31,12 @@ class DebGenerator
 public:
   DebGenerator(cmCPackLog* logger, std::string outputName, std::string workDir,
                std::string topLevelDir, std::string temporaryDir,
-               const char* debianCompressionType, const char* numThreads,
-               const char* debianArchiveType,
+               cmValue debianCompressionType, cmValue numThreads,
+               cmValue debianArchiveType,
                std::map<std::string, std::string> controlValues,
                bool genShLibs, std::string shLibsFilename, bool genPostInst,
                std::string postInst, bool genPostRm, std::string postRm,
-               const char* controlExtra, bool permissionStrctPolicy,
+               cmValue controlExtra, bool permissionStrctPolicy,
                std::vector<std::string> packageFiles);
 
   bool generate() const;
@@ -53,8 +55,8 @@ private:
   std::string CompressionSuffix;
   const std::string TopLevelDir;
   const std::string TemporaryDir;
-  const char* DebianArchiveType;
-  int NumThreads;
+  const std::string DebianArchiveType;
+  long NumThreads;
   const std::map<std::string, std::string> ControlValues;
   const bool GenShLibs;
   const std::string ShLibsFilename;
@@ -62,7 +64,7 @@ private:
   const std::string PostInst;
   const bool GenPostRm;
   const std::string PostRm;
-  const char* ControlExtra;
+  cmValue ControlExtra;
   const bool PermissionStrictPolicy;
   const std::vector<std::string> PackageFiles;
   cmArchiveWrite::Compress TarCompressionType;
@@ -71,18 +73,17 @@ private:
 DebGenerator::DebGenerator(
   cmCPackLog* logger, std::string outputName, std::string workDir,
   std::string topLevelDir, std::string temporaryDir,
-  const char* debianCompressionType, const char* numThreads,
-  const char* debianArchiveType,
+  cmValue debCompressionType, cmValue numThreads, cmValue debianArchiveType,
   std::map<std::string, std::string> controlValues, bool genShLibs,
   std::string shLibsFilename, bool genPostInst, std::string postInst,
-  bool genPostRm, std::string postRm, const char* controlExtra,
+  bool genPostRm, std::string postRm, cmValue controlExtra,
   bool permissionStrictPolicy, std::vector<std::string> packageFiles)
   : Logger(logger)
   , OutputName(std::move(outputName))
   , WorkDir(std::move(workDir))
   , TopLevelDir(std::move(topLevelDir))
   , TemporaryDir(std::move(temporaryDir))
-  , DebianArchiveType(debianArchiveType ? debianArchiveType : "gnutar")
+  , DebianArchiveType(debianArchiveType ? *debianArchiveType : "gnutar")
   , ControlValues(std::move(controlValues))
   , GenShLibs(genShLibs)
   , ShLibsFilename(std::move(shLibsFilename))
@@ -94,23 +95,27 @@ DebGenerator::DebGenerator(
   , PermissionStrictPolicy(permissionStrictPolicy)
   , PackageFiles(std::move(packageFiles))
 {
-  if (!debianCompressionType) {
-    debianCompressionType = "gzip";
+  std::string debianCompressionType = "gzip";
+  if (debCompressionType) {
+    debianCompressionType = *debCompressionType;
   }
 
-  if (!strcmp(debianCompressionType, "lzma")) {
+  if (debianCompressionType == "lzma") {
     this->CompressionSuffix = ".lzma";
     this->TarCompressionType = cmArchiveWrite::CompressLZMA;
-  } else if (!strcmp(debianCompressionType, "xz")) {
+  } else if (debianCompressionType == "xz") {
     this->CompressionSuffix = ".xz";
     this->TarCompressionType = cmArchiveWrite::CompressXZ;
-  } else if (!strcmp(debianCompressionType, "bzip2")) {
+  } else if (debianCompressionType == "bzip2") {
     this->CompressionSuffix = ".bz2";
     this->TarCompressionType = cmArchiveWrite::CompressBZip2;
-  } else if (!strcmp(debianCompressionType, "gzip")) {
+  } else if (debianCompressionType == "gzip") {
     this->CompressionSuffix = ".gz";
     this->TarCompressionType = cmArchiveWrite::CompressGZip;
-  } else if (!strcmp(debianCompressionType, "none")) {
+  } else if (debianCompressionType == "zstd") {
+    this->CompressionSuffix = ".zst";
+    this->TarCompressionType = cmArchiveWrite::CompressZstd;
+  } else if (debianCompressionType == "none") {
     this->CompressionSuffix.clear();
     this->TarCompressionType = cmArchiveWrite::CompressNone;
   } else {
@@ -119,16 +124,15 @@ DebGenerator::DebGenerator(
                     << debianCompressionType << std::endl);
   }
 
-  if (numThreads == nullptr) {
-    numThreads = "1";
-  }
-
-  char* endptr;
-  this->NumThreads = static_cast<int>(strtol(numThreads, &endptr, 10));
-  if (numThreads != endptr && *endptr != '\0') {
-    cmCPackLogger(cmCPackLog::LOG_ERROR,
-                  "Unrecognized number of threads: " << numThreads
-                                                     << std::endl);
+  if (numThreads != nullptr) {
+    if (!cmStrToLong(numThreads, &this->NumThreads)) {
+      this->NumThreads = 1;
+      cmCPackLogger(cmCPackLog::LOG_ERROR,
+                    "Unrecognized number of threads: " << numThreads
+                                                       << std::endl);
+    }
+  } else {
+    this->NumThreads = 1;
   }
 }
 
@@ -187,8 +191,15 @@ bool DebGenerator::generateDataTar() const
     return false;
   }
   cmArchiveWrite data_tar(fileStream_data_tar, this->TarCompressionType,
-                          this->DebianArchiveType, 0, this->NumThreads);
-  data_tar.Open();
+                          this->DebianArchiveType, 0,
+                          static_cast<int>(this->NumThreads));
+  if (!data_tar.Open()) {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+                  "Error opening the archive \""
+                    << filename_data_tar
+                    << "\", ERROR = " << data_tar.GetError() << std::endl);
+    return false;
+  }
 
   // uid/gid should be the one of the root user, and this root user has
   // always uid/gid equal to 0.
@@ -248,11 +259,15 @@ bool DebGenerator::generateDataTar() const
     // do not recurse because the loop will do it
     if (!data_tar.Add(file, topLevelLength, ".", false)) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "Problem adding file to tar:"
-                      << std::endl
-                      << "#top level directory: " << this->WorkDir << std::endl
-                      << "#file: " << file << std::endl
-                      << "#error:" << data_tar.GetError() << std::endl);
+                    "Problem adding file to tar:\n"
+                    "#top level directory: "
+                      << this->WorkDir
+                      << "\n"
+                         "#file: "
+                      << file
+                      << "\n"
+                         "#error:"
+                      << data_tar.GetError() << std::endl);
       return false;
     }
   }
@@ -309,7 +324,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
   cmArchiveWrite control_tar(fileStream_control_tar,
                              cmArchiveWrite::CompressGZip,
                              this->DebianArchiveType);
-  control_tar.Open();
+  if (!control_tar.Open()) {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+                  "Error opening the archive \""
+                    << filename_control_tar
+                    << "\", ERROR = " << control_tar.GetError() << std::endl);
+    return false;
+  }
 
   // sets permissions and uid/gid for the files
   control_tar.SetUIDAndGID(0u, 0u);
@@ -334,11 +355,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
       !control_tar.Add(this->WorkDir + "/control", this->WorkDir.length(),
                        ".")) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
-                  "Error adding file to tar:"
-                    << std::endl
-                    << "#top level directory: " << this->WorkDir << std::endl
-                    << "#file: \"control\" or \"md5sums\"" << std::endl
-                    << "#error:" << control_tar.GetError() << std::endl);
+                  "Error adding file to tar:\n"
+                  "#top level directory: "
+                    << this->WorkDir
+                    << "\n"
+                       "#file: \"control\" or \"md5sums\"\n"
+                       "#error:"
+                    << control_tar.GetError() << std::endl);
     return false;
   }
 
@@ -346,11 +369,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
   if (this->GenShLibs) {
     if (!control_tar.Add(this->ShLibsFilename, this->WorkDir.length(), ".")) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "Error adding file to tar:"
-                      << std::endl
-                      << "#top level directory: " << this->WorkDir << std::endl
-                      << "#file: \"shlibs\"" << std::endl
-                      << "#error:" << control_tar.GetError() << std::endl);
+                    "Error adding file to tar:\n"
+                    "#top level directory: "
+                      << this->WorkDir
+                      << "\n"
+                         "#file: \"shlibs\"\n"
+                         "#error:"
+                      << control_tar.GetError() << std::endl);
       return false;
     }
   }
@@ -360,11 +385,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
     control_tar.SetPermissions(permission755);
     if (!control_tar.Add(this->PostInst, this->WorkDir.length(), ".")) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "Error adding file to tar:"
-                      << std::endl
-                      << "#top level directory: " << this->WorkDir << std::endl
-                      << "#file: \"postinst\"" << std::endl
-                      << "#error:" << control_tar.GetError() << std::endl);
+                    "Error adding file to tar:\n"
+                    "#top level directory: "
+                      << this->WorkDir
+                      << "\n"
+                         "#file: \"postinst\"\n"
+                         "#error:"
+                      << control_tar.GetError() << std::endl);
       return false;
     }
     control_tar.SetPermissions(permission644);
@@ -374,11 +401,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
     control_tar.SetPermissions(permission755);
     if (!control_tar.Add(this->PostRm, this->WorkDir.length(), ".")) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "Error adding file to tar:"
-                      << std::endl
-                      << "#top level directory: " << this->WorkDir << std::endl
-                      << "#file: \"postinst\"" << std::endl
-                      << "#error:" << control_tar.GetError() << std::endl);
+                    "Error adding file to tar:\n"
+                    "#top level directory: "
+                      << this->WorkDir
+                      << "\n"
+                         "#file: \"postinst\"\n"
+                         "#error:"
+                      << control_tar.GetError() << std::endl);
       return false;
     }
     control_tar.SetPermissions(permission644);
@@ -412,11 +441,12 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
       // if we can copy the file, it means it does exist, let's add it:
       if (!cmsys::SystemTools::FileExists(i)) {
         cmCPackLogger(cmCPackLog::LOG_WARNING,
-                      "Adding file to tar:" << std::endl
-                                            << "#top level directory: "
-                                            << this->WorkDir << std::endl
-                                            << "#missing file: " << i
-                                            << std::endl);
+                      "Adding file to tar:\n"
+                      "#top level directory: "
+                        << this->WorkDir
+                        << "\n"
+                           "#missing file: "
+                        << i << std::endl);
       }
 
       if (cmsys::SystemTools::CopyFileIfDifferent(i, localcopy)) {
@@ -440,7 +470,13 @@ bool DebGenerator::generateDeb() const
   cmGeneratedFileStream debStream;
   debStream.Open(outputPath, false, true);
   cmArchiveWrite deb(debStream, cmArchiveWrite::CompressNone, "arbsd");
-  deb.Open();
+  if (!deb.Open()) {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+                  "Error opening the archive \""
+                    << outputPath << "\", ERROR = " << deb.GetError()
+                    << std::endl);
+    return false;
+  }
 
   // uid/gid should be the one of the root user, and this root user has
   // always uid/gid equal to 0.
@@ -451,17 +487,37 @@ bool DebGenerator::generateDeb() const
       !deb.Add(tlDir + "control.tar.gz", tlDir.length()) ||
       !deb.Add(tlDir + "data.tar" + this->CompressionSuffix, tlDir.length())) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
-                  "Error creating debian package:"
-                    << std::endl
-                    << "#top level directory: " << this->TopLevelDir
-                    << std::endl
-                    << "#file: " << this->OutputName << std::endl
-                    << "#error:" << deb.GetError() << std::endl);
+                  "Error creating debian package:\n"
+                  "#top level directory: "
+                    << this->TopLevelDir
+                    << "\n"
+                       "#file: "
+                    << this->OutputName
+                    << "\n"
+                       "#error:"
+                    << deb.GetError() << std::endl);
     return false;
   }
   return true;
 }
 
+std::vector<std::string> findFilesIn(const std::string& path)
+{
+  cmsys::Glob gl;
+  std::string findExpr = path + "/*";
+  gl.RecurseOn();
+  gl.SetRecurseListDirs(true);
+  gl.SetRecurseThroughSymlinks(false);
+  if (!gl.FindFiles(findExpr)) {
+    throw std::runtime_error(
+      "Cannot find any files in the installed directory");
+  }
+  std::vector<std::string> files{ gl.GetFiles() };
+  // Sort files so that they have a reproducible order
+  std::sort(files.begin(), files.end());
+  return files;
+}
+
 } // end anonymous namespace
 
 cmCPackDebGenerator::cmCPackDebGenerator() = default;
@@ -480,128 +536,71 @@ int cmCPackDebGenerator::InitializeInternal()
 int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
                                         std::string const& packageName)
 {
-  int retval = 1;
   // Begin the archive for this pack
   std::string localToplevel(initialTopLevel);
   std::string packageFileName(
     cmSystemTools::GetParentDirectory(this->toplevel));
-  std::string outputFileName(
-    std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + "-" +
-    packageName + this->GetOutputExtension());
+  std::string outputFileName(*this->GetOption("CPACK_PACKAGE_FILE_NAME") +
+                             "-" + packageName + this->GetOutputExtension());
 
   localToplevel += "/" + packageName;
   /* replace the TEMP DIRECTORY with the component one */
-  this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
+  this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel);
   packageFileName += "/" + outputFileName;
   /* replace proposed CPACK_OUTPUT_FILE_NAME */
-  this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
+  this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName);
   /* replace the TEMPORARY package file name */
-  this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
-                  packageFileName.c_str());
+  this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME", packageFileName);
   // Tell CPackDeb.cmake the name of the component GROUP.
-  this->SetOption("CPACK_DEB_PACKAGE_COMPONENT", packageName.c_str());
+  this->SetOption("CPACK_DEB_PACKAGE_COMPONENT", packageName);
   // Tell CPackDeb.cmake the path where the component is.
   std::string component_path = cmStrCat('/', packageName);
-  this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH",
-                  component_path.c_str());
+  this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH", component_path);
   if (!this->ReadListFile("Internal/CPack/CPackDeb.cmake")) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Error while execution CPackDeb.cmake" << std::endl);
-    retval = 0;
-    return retval;
-  }
-
-  { // Isolate globbing of binaries vs. dbgsyms
-    cmsys::Glob gl;
-    std::string findExpr(this->GetOption("GEN_WDIR"));
-    findExpr += "/*";
-    gl.RecurseOn();
-    gl.SetRecurseListDirs(true);
-    gl.SetRecurseThroughSymlinks(false);
-    if (!gl.FindFiles(findExpr)) {
-      cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "Cannot find any files in the installed directory"
-                      << std::endl);
-      return 0;
-    }
-    this->packageFiles = gl.GetFiles();
-  }
-
-  int res = this->createDeb();
-  if (res != 1) {
-    retval = 0;
-  }
-  // add the generated package to package file names list
-  packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
-                             this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"));
-  this->packageFileNames.push_back(std::move(packageFileName));
-
-  if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE") &&
-      this->GetOption("GEN_DBGSYMDIR")) {
-    cmsys::Glob gl;
-    std::string findExpr(this->GetOption("GEN_DBGSYMDIR"));
-    findExpr += "/*";
-    gl.RecurseOn();
-    gl.SetRecurseListDirs(true);
-    gl.SetRecurseThroughSymlinks(false);
-    if (!gl.FindFiles(findExpr)) {
-      cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "Cannot find any files in the installed directory"
-                      << std::endl);
-      return 0;
-    }
-    this->packageFiles = gl.GetFiles();
-
-    res = this->createDbgsymDDeb();
-    if (res != 1) {
-      retval = 0;
-    }
-    // add the generated package to package file names list
-    packageFileName =
-      cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
-               this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"));
-    this->packageFileNames.push_back(std::move(packageFileName));
+    return 0;
   }
 
-  return retval;
+  return this->createDebPackages();
 }
 
 int cmCPackDebGenerator::PackageComponents(bool ignoreGroup)
 {
-  int retval = 1;
-  /* Reset package file name list it will be populated during the
-   * component packaging run*/
+  // Reset package file name list it will be populated during the
+  // component packaging run
   this->packageFileNames.clear();
   std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
 
+  int retval = 1;
   // The default behavior is to have one package by component group
   // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
-  if (!ignoreGroup) {
-    for (auto const& compG : this->ComponentGroups) {
-      cmCPackLogger(cmCPackLog::LOG_VERBOSE,
-                    "Packaging component group: " << compG.first << std::endl);
-      // Begin the archive for this group
-      retval &= this->PackageOnePack(initialTopLevel, compG.first);
-    }
-    // Handle Orphan components (components not belonging to any groups)
+  if (ignoreGroup) {
+    // CPACK_COMPONENTS_IGNORE_GROUPS is set
+    // We build 1 package per component
     for (auto const& comp : this->Components) {
-      // Does the component belong to a group?
-      if (comp.second.Group == nullptr) {
-        cmCPackLogger(
-          cmCPackLog::LOG_VERBOSE,
-          "Component <"
-            << comp.second.Name
-            << "> does not belong to any group, package it separately."
-            << std::endl);
-        // Begin the archive for this orphan component
-        retval &= this->PackageOnePack(initialTopLevel, comp.first);
-      }
+      retval &= this->PackageOnePack(initialTopLevel, comp.first);
     }
+    return retval;
   }
-  // CPACK_COMPONENTS_IGNORE_GROUPS is set
-  // We build 1 package per component
-  else {
-    for (auto const& comp : this->Components) {
+
+  for (auto const& compG : this->ComponentGroups) {
+    cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+                  "Packaging component group: " << compG.first << std::endl);
+    // Begin the archive for this group
+    retval &= this->PackageOnePack(initialTopLevel, compG.first);
+  }
+  // Handle Orphan components (components not belonging to any groups)
+  for (auto const& comp : this->Components) {
+    // Does the component belong to a group?
+    if (comp.second.Group == nullptr) {
+      cmCPackLogger(
+        cmCPackLog::LOG_VERBOSE,
+        "Component <"
+          << comp.second.Name
+          << "> does not belong to any group, package it separately."
+          << std::endl);
+      // Begin the archive for this orphan component
       retval &= this->PackageOnePack(initialTopLevel, comp.first);
     }
   }
@@ -612,7 +611,6 @@ int cmCPackDebGenerator::PackageComponents(bool ignoreGroup)
 int cmCPackDebGenerator::PackageComponentsAllInOne(
   const std::string& compInstDirName)
 {
-  int retval = 1;
   /* Reset package file name list it will be populated during the
    * component packaging run*/
   this->packageFileNames.clear();
@@ -627,9 +625,8 @@ int cmCPackDebGenerator::PackageComponentsAllInOne(
   std::string localToplevel(initialTopLevel);
   std::string packageFileName(
     cmSystemTools::GetParentDirectory(this->toplevel));
-  std::string outputFileName(
-    std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
-    this->GetOutputExtension());
+  std::string outputFileName(*this->GetOption("CPACK_PACKAGE_FILE_NAME") +
+                             this->GetOutputExtension());
   // all GROUP in one vs all COMPONENT in one
   // if must be here otherwise non component paths have a trailing / while
   // components don't
@@ -638,50 +635,25 @@ int cmCPackDebGenerator::PackageComponentsAllInOne(
   }
 
   /* replace the TEMP DIRECTORY with the component one */
-  this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
+  this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel);
   packageFileName += "/" + outputFileName;
   /* replace proposed CPACK_OUTPUT_FILE_NAME */
-  this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
+  this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName);
   /* replace the TEMPORARY package file name */
-  this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
-                  packageFileName.c_str());
+  this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME", packageFileName);
 
   if (!compInstDirName.empty()) {
     // Tell CPackDeb.cmake the path where the component is.
     std::string component_path = cmStrCat('/', compInstDirName);
-    this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH",
-                    component_path.c_str());
+    this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH", component_path);
   }
   if (!this->ReadListFile("Internal/CPack/CPackDeb.cmake")) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Error while execution CPackDeb.cmake" << std::endl);
-    retval = 0;
-    return retval;
-  }
-
-  cmsys::Glob gl;
-  std::string findExpr(this->GetOption("GEN_WDIR"));
-  findExpr += "/*";
-  gl.RecurseOn();
-  gl.SetRecurseListDirs(true);
-  gl.SetRecurseThroughSymlinks(false);
-  if (!gl.FindFiles(findExpr)) {
-    cmCPackLogger(cmCPackLog::LOG_ERROR,
-                  "Cannot find any files in the installed directory"
-                    << std::endl);
     return 0;
   }
-  this->packageFiles = gl.GetFiles();
 
-  int res = this->createDeb();
-  if (res != 1) {
-    retval = 0;
-  }
-  // add the generated package to package file names list
-  packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
-                             this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"));
-  this->packageFileNames.push_back(std::move(packageFileName));
-  return retval;
+  return this->createDebPackages();
 }
 
 int cmCPackDebGenerator::PackageFiles()
@@ -705,7 +677,40 @@ int cmCPackDebGenerator::PackageFiles()
   return this->PackageComponentsAllInOne("");
 }
 
-int cmCPackDebGenerator::createDeb()
+bool cmCPackDebGenerator::createDebPackages()
+{
+  auto make_package = [this](const std::string& path,
+                             const char* const output_var,
+                             bool (cmCPackDebGenerator::*creator)()) -> bool {
+    try {
+      this->packageFiles = findFilesIn(path);
+    } catch (const std::runtime_error& ex) {
+      cmCPackLogger(cmCPackLog::LOG_ERROR, ex.what() << std::endl);
+      return false;
+    }
+
+    if ((this->*creator)()) {
+      // add the generated package to package file names list
+      this->packageFileNames.emplace_back(
+        cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
+                 this->GetOption(output_var)));
+      return true;
+    }
+    return false;
+  };
+  bool retval =
+    make_package(this->GetOption("GEN_WDIR"), "GEN_CPACK_OUTPUT_FILE_NAME",
+                 &cmCPackDebGenerator::createDeb);
+  cmValue dbgsymdir_path = this->GetOption("GEN_DBGSYMDIR");
+  if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE") && dbgsymdir_path) {
+    retval = make_package(dbgsymdir_path, "GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME",
+                          &cmCPackDebGenerator::createDbgsymDDeb) &&
+      retval;
+  }
+  return int(retval);
+}
+
+bool cmCPackDebGenerator::createDeb()
 {
   std::map<std::string, std::string> controlValues;
 
@@ -713,78 +718,77 @@ int cmCPackDebGenerator::createDeb()
   controlValues["Package"] = cmsys::SystemTools::LowerCase(
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME"));
   controlValues["Version"] =
-    this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
+    *this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
   controlValues["Section"] =
-    this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SECTION");
+    *this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SECTION");
   controlValues["Priority"] =
-    this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PRIORITY");
+    *this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PRIORITY");
   controlValues["Architecture"] =
-    this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
+    *this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
   controlValues["Maintainer"] =
-    this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
+    *this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
   controlValues["Description"] =
-    this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DESCRIPTION");
+    *this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DESCRIPTION");
 
-  const char* debian_pkg_source =
+  cmValue debian_pkg_source =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
   if (cmNonempty(debian_pkg_source)) {
-    controlValues["Source"] = debian_pkg_source;
+    controlValues["Source"] = *debian_pkg_source;
   }
-  const char* debian_pkg_dep =
-    this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DEPENDS");
+  cmValue debian_pkg_dep = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DEPENDS");
   if (cmNonempty(debian_pkg_dep)) {
-    controlValues["Depends"] = debian_pkg_dep;
+    controlValues["Depends"] = *debian_pkg_dep;
   }
-  const char* debian_pkg_rec =
+  cmValue debian_pkg_rec =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_RECOMMENDS");
   if (cmNonempty(debian_pkg_rec)) {
-    controlValues["Recommends"] = debian_pkg_rec;
+    controlValues["Recommends"] = *debian_pkg_rec;
   }
-  const char* debian_pkg_sug =
+  cmValue debian_pkg_sug =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SUGGESTS");
   if (cmNonempty(debian_pkg_sug)) {
-    controlValues["Suggests"] = debian_pkg_sug;
+    controlValues["Suggests"] = *debian_pkg_sug;
   }
-  const char* debian_pkg_url =
+  cmValue debian_pkg_url =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_HOMEPAGE");
   if (cmNonempty(debian_pkg_url)) {
-    controlValues["Homepage"] = debian_pkg_url;
+    controlValues["Homepage"] = *debian_pkg_url;
   }
-  const char* debian_pkg_predep =
+  cmValue debian_pkg_predep =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PREDEPENDS");
   if (cmNonempty(debian_pkg_predep)) {
-    controlValues["Pre-Depends"] = debian_pkg_predep;
+    controlValues["Pre-Depends"] = *debian_pkg_predep;
   }
-  const char* debian_pkg_enhances =
+  cmValue debian_pkg_enhances =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ENHANCES");
   if (cmNonempty(debian_pkg_enhances)) {
-    controlValues["Enhances"] = debian_pkg_enhances;
+    controlValues["Enhances"] = *debian_pkg_enhances;
   }
-  const char* debian_pkg_breaks =
+  cmValue debian_pkg_breaks =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_BREAKS");
   if (cmNonempty(debian_pkg_breaks)) {
-    controlValues["Breaks"] = debian_pkg_breaks;
+    controlValues["Breaks"] = *debian_pkg_breaks;
   }
-  const char* debian_pkg_conflicts =
+  cmValue debian_pkg_conflicts =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONFLICTS");
   if (cmNonempty(debian_pkg_conflicts)) {
-    controlValues["Conflicts"] = debian_pkg_conflicts;
+    controlValues["Conflicts"] = *debian_pkg_conflicts;
   }
-  const char* debian_pkg_provides =
+  cmValue debian_pkg_provides =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PROVIDES");
   if (cmNonempty(debian_pkg_provides)) {
-    controlValues["Provides"] = debian_pkg_provides;
+    controlValues["Provides"] = *debian_pkg_provides;
   }
-  const char* debian_pkg_replaces =
+  cmValue debian_pkg_replaces =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_REPLACES");
   if (cmNonempty(debian_pkg_replaces)) {
-    controlValues["Replaces"] = debian_pkg_replaces;
+    controlValues["Replaces"] = *debian_pkg_replaces;
   }
 
   const std::string strGenWDIR(this->GetOption("GEN_WDIR"));
   const std::string shlibsfilename = strGenWDIR + "/shlibs";
 
-  const char* debian_pkg_shlibs =
+  cmValue debian_pkg_shlibs =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SHLIBS");
   const bool gen_shibs = this->IsOn("CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS") &&
     cmNonempty(debian_pkg_shlibs);
@@ -829,13 +833,10 @@ int cmCPackDebGenerator::createDeb()
     this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
     this->packageFiles);
 
-  if (!gen.generate()) {
-    return 0;
-  }
-  return 1;
+  return gen.generate();
 }
 
-int cmCPackDebGenerator::createDbgsymDDeb()
+bool cmCPackDebGenerator::createDbgsymDDeb()
 {
   // Packages containing debug symbols follow the same structure as .debs
   // but have different metadata and content.
@@ -844,38 +845,38 @@ int cmCPackDebGenerator::createDbgsymDDeb()
   // debian policy enforce lower case for package name
   std::string packageNameLower = cmsys::SystemTools::LowerCase(
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME"));
-  const char* debian_pkg_version =
+  cmValue debian_pkg_version =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
 
   controlValues["Package"] = packageNameLower + "-dbgsym";
   controlValues["Package-Type"] = "ddeb";
-  controlValues["Version"] = debian_pkg_version;
+  controlValues["Version"] = *debian_pkg_version;
   controlValues["Auto-Built-Package"] = "debug-symbols";
-  controlValues["Depends"] = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME") +
-    std::string(" (= ") + debian_pkg_version + ")";
+  controlValues["Depends"] =
+    *this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME") + std::string(" (= ") +
+    *debian_pkg_version + ")";
   controlValues["Section"] = "debug";
   controlValues["Priority"] = "optional";
   controlValues["Architecture"] =
-    this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
+    *this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
   controlValues["Maintainer"] =
-    this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
+    *this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
   controlValues["Description"] =
     std::string("debug symbols for ") + packageNameLower;
 
-  const char* debian_pkg_source =
+  cmValue debian_pkg_source =
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
   if (cmNonempty(debian_pkg_source)) {
-    controlValues["Source"] = debian_pkg_source;
+    controlValues["Source"] = *debian_pkg_source;
   }
-  const char* debian_build_ids = this->GetOption("GEN_BUILD_IDS");
+  cmValue debian_build_ids = this->GetOption("GEN_BUILD_IDS");
   if (cmNonempty(debian_build_ids)) {
-    controlValues["Build-Ids"] = debian_build_ids;
+    controlValues["Build-Ids"] = *debian_build_ids;
   }
 
   DebGenerator gen(
     this->Logger, this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"),
     this->GetOption("GEN_DBGSYMDIR"),
-
     this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
     this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
     this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
@@ -885,10 +886,7 @@ int cmCPackDebGenerator::createDbgsymDDeb()
     this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
     this->packageFiles);
 
-  if (!gen.generate()) {
-    return 0;
-  }
-  return 1;
+  return gen.generate();
 }
 
 bool cmCPackDebGenerator::SupportsComponentInstallation() const
@@ -911,7 +909,7 @@ std::string cmCPackDebGenerator::GetComponentInstallDirNameSuffix(
   std::string groupVar =
     "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
   if (nullptr != this->GetOption(groupVar)) {
-    return std::string(this->GetOption(groupVar));
+    return *this->GetOption(groupVar);
   }
   return componentName;
 }
index ee8f39a..61a6616 100644 (file)
@@ -63,8 +63,9 @@ protected:
     const std::string& componentName) override;
 
 private:
-  int createDeb();
-  int createDbgsymDDeb();
+  bool createDebPackages();
+  bool createDeb();
+  bool createDbgsymDDeb();
 
   std::vector<std::string> packageFiles;
 };
index b71c969..9385a5a 100644 (file)
@@ -20,6 +20,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmXMLWriter.h"
 
 #ifdef HAVE_CoreServices
@@ -76,7 +77,7 @@ int cmCPackDragNDropGenerator::InitializeInternal()
                   "Cannot locate hdiutil command" << std::endl);
     return 0;
   }
-  this->SetOptionIfNotSet("CPACK_COMMAND_HDIUTIL", hdiutil_path.c_str());
+  this->SetOptionIfNotSet("CPACK_COMMAND_HDIUTIL", hdiutil_path);
 
   const std::string setfile_path =
     cmSystemTools::FindProgram("SetFile", paths, false);
@@ -85,7 +86,7 @@ int cmCPackDragNDropGenerator::InitializeInternal()
                   "Cannot locate SetFile command" << std::endl);
     return 0;
   }
-  this->SetOptionIfNotSet("CPACK_COMMAND_SETFILE", setfile_path.c_str());
+  this->SetOptionIfNotSet("CPACK_COMMAND_SETFILE", setfile_path);
 
   const std::string rez_path = cmSystemTools::FindProgram("Rez", paths, false);
   if (rez_path.empty()) {
@@ -93,7 +94,7 @@ int cmCPackDragNDropGenerator::InitializeInternal()
                   "Cannot locate Rez command" << std::endl);
     return 0;
   }
-  this->SetOptionIfNotSet("CPACK_COMMAND_REZ", rez_path.c_str());
+  this->SetOptionIfNotSet("CPACK_COMMAND_REZ", rez_path);
 
   if (this->IsSet("CPACK_DMG_SLA_DIR")) {
     slaDirectory = this->GetOption("CPACK_DMG_SLA_DIR");
@@ -260,48 +261,35 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
                                          const std::string& output_file)
 {
   // Get optional arguments ...
-  const std::string cpack_package_icon = this->GetOption("CPACK_PACKAGE_ICON")
-    ? this->GetOption("CPACK_PACKAGE_ICON")
-    : "";
+  cmValue cpack_package_icon = this->GetOption("CPACK_PACKAGE_ICON");
 
   const std::string cpack_dmg_volume_name =
     this->GetOption("CPACK_DMG_VOLUME_NAME")
-    ? this->GetOption("CPACK_DMG_VOLUME_NAME")
-    : this->GetOption("CPACK_PACKAGE_FILE_NAME");
+    ? *this->GetOption("CPACK_DMG_VOLUME_NAME")
+    : *this->GetOption("CPACK_PACKAGE_FILE_NAME");
 
   const std::string cpack_dmg_format = this->GetOption("CPACK_DMG_FORMAT")
-    ? this->GetOption("CPACK_DMG_FORMAT")
+    ? *this->GetOption("CPACK_DMG_FORMAT")
     : "UDZO";
 
   const std::string cpack_dmg_filesystem =
     this->GetOption("CPACK_DMG_FILESYSTEM")
-    ? this->GetOption("CPACK_DMG_FILESYSTEM")
+    ? *this->GetOption("CPACK_DMG_FILESYSTEM")
     : "HFS+";
 
   // Get optional arguments ...
   std::string cpack_license_file =
-    this->GetOption("CPACK_RESOURCE_FILE_LICENSE")
-    ? this->GetOption("CPACK_RESOURCE_FILE_LICENSE")
-    : "";
+    *this->GetOption("CPACK_RESOURCE_FILE_LICENSE");
 
-  const std::string cpack_dmg_background_image =
-    this->GetOption("CPACK_DMG_BACKGROUND_IMAGE")
-    ? this->GetOption("CPACK_DMG_BACKGROUND_IMAGE")
-    : "";
+  cmValue cpack_dmg_background_image =
+    this->GetOption("CPACK_DMG_BACKGROUND_IMAGE");
 
-  const std::string cpack_dmg_ds_store = this->GetOption("CPACK_DMG_DS_STORE")
-    ? this->GetOption("CPACK_DMG_DS_STORE")
-    : "";
+  cmValue cpack_dmg_ds_store = this->GetOption("CPACK_DMG_DS_STORE");
 
-  const std::string cpack_dmg_languages =
-    this->GetOption("CPACK_DMG_SLA_LANGUAGES")
-    ? this->GetOption("CPACK_DMG_SLA_LANGUAGES")
-    : "";
+  cmValue cpack_dmg_languages = this->GetOption("CPACK_DMG_SLA_LANGUAGES");
 
-  const std::string cpack_dmg_ds_store_setup_script =
-    this->GetOption("CPACK_DMG_DS_STORE_SETUP_SCRIPT")
-    ? this->GetOption("CPACK_DMG_DS_STORE_SETUP_SCRIPT")
-    : "";
+  cmValue cpack_dmg_ds_store_setup_script =
+    this->GetOption("CPACK_DMG_DS_STORE_SETUP_SCRIPT");
 
   const bool cpack_dmg_disable_applications_symlink =
     this->IsOn("CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK");
@@ -332,7 +320,7 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
   }
 
   // Optionally add a custom volume icon ...
-  if (!cpack_package_icon.empty()) {
+  if (!cpack_package_icon->empty()) {
     std::ostringstream package_icon_source;
     package_icon_source << cpack_package_icon;
 
@@ -351,7 +339,7 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
 
   // Optionally add a custom .DS_Store file
   // (e.g. for setting background/layout) ...
-  if (!cpack_dmg_ds_store.empty()) {
+  if (!cpack_dmg_ds_store->empty()) {
     std::ostringstream package_settings_source;
     package_settings_source << cpack_dmg_ds_store;
 
@@ -372,7 +360,7 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
   // Optionally add a custom background image ...
   // Make sure the background file type is the same as the custom image
   // and that the file is hidden so it doesn't show up.
-  if (!cpack_dmg_background_image.empty()) {
+  if (!cpack_dmg_background_image->empty()) {
     const std::string extension =
       cmSystemTools::GetFilenameLastExtension(cpack_dmg_background_image);
     std::ostringstream package_background_source;
@@ -394,7 +382,7 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
   }
 
   bool remount_image =
-    !cpack_package_icon.empty() || !cpack_dmg_ds_store_setup_script.empty();
+    !cpack_package_icon->empty() || !cpack_dmg_ds_store_setup_script->empty();
 
   std::string temp_image_format = "UDZO";
 
@@ -471,7 +459,7 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
     }
 
     // Optionally set the custom icon flag for the image ...
-    if (!had_error && !cpack_package_icon.empty()) {
+    if (!had_error && !cpack_package_icon->empty()) {
       std::string error;
       std::ostringstream setfile_command;
       setfile_command << this->GetOption("CPACK_COMMAND_SETFILE");
@@ -490,7 +478,7 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
 
     // Optionally we can execute a custom apple script to generate
     // the .DS_Store for the volume folder ...
-    if (!had_error && !cpack_dmg_ds_store_setup_script.empty()) {
+    if (!had_error && !cpack_dmg_ds_store_setup_script->empty()) {
       std::ostringstream setup_script_command;
       setup_script_command << "osascript"
                            << " \"" << cpack_dmg_ds_store_setup_script << "\""
@@ -718,7 +706,7 @@ std::string cmCPackDragNDropGenerator::GetComponentInstallDirNameSuffix(
     // the current COMPONENT belongs to.
     std::string groupVar =
       "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
-    const char* _groupName = GetOption(groupVar);
+    cmValue _groupName = this->GetOption(groupVar);
     if (_groupName) {
       std::string groupName = _groupName;
 
index e3521a0..157ee1d 100644 (file)
@@ -18,6 +18,7 @@
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 int cmCPackExternalGenerator::InitializeInternal()
 {
@@ -60,7 +61,7 @@ int cmCPackExternalGenerator::PackageFiles()
     return 0;
   }
 
-  const char* packageScript = this->GetOption("CPACK_EXTERNAL_PACKAGE_SCRIPT");
+  cmValue packageScript = this->GetOption("CPACK_EXTERNAL_PACKAGE_SCRIPT");
   if (cmNonempty(packageScript)) {
     if (!cmSystemTools::FileIsFullPath(packageScript)) {
       cmCPackLogger(
@@ -76,10 +77,9 @@ int cmCPackExternalGenerator::PackageFiles()
       return 0;
     }
 
-    const char* builtPackagesStr =
-      this->GetOption("CPACK_EXTERNAL_BUILT_PACKAGES");
-    if (builtPackagesStr) {
-      cmExpandList(builtPackagesStr, this->packageFileNames, false);
+    cmValue builtPackages = this->GetOption("CPACK_EXTERNAL_BUILT_PACKAGES");
+    if (builtPackages) {
+      cmExpandList(builtPackages, this->packageFileNames, false);
     }
   }
 
@@ -181,43 +181,42 @@ int cmCPackExternalGenerator::cmCPackExternalVersionGenerator::WriteToJSON(
     return 0;
   }
 
-  const char* packageName = this->Parent->GetOption("CPACK_PACKAGE_NAME");
+  cmValue packageName = this->Parent->GetOption("CPACK_PACKAGE_NAME");
   if (packageName) {
-    root["packageName"] = packageName;
+    root["packageName"] = *packageName;
   }
 
-  const char* packageVersion =
-    this->Parent->GetOption("CPACK_PACKAGE_VERSION");
+  cmValue packageVersion = this->Parent->GetOption("CPACK_PACKAGE_VERSION");
   if (packageVersion) {
-    root["packageVersion"] = packageVersion;
+    root["packageVersion"] = *packageVersion;
   }
 
-  const char* packageDescriptionFile =
+  cmValue packageDescriptionFile =
     this->Parent->GetOption("CPACK_PACKAGE_DESCRIPTION_FILE");
   if (packageDescriptionFile) {
-    root["packageDescriptionFile"] = packageDescriptionFile;
+    root["packageDescriptionFile"] = *packageDescriptionFile;
   }
 
-  const char* packageDescriptionSummary =
+  cmValue packageDescriptionSummary =
     this->Parent->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY");
   if (packageDescriptionSummary) {
-    root["packageDescriptionSummary"] = packageDescriptionSummary;
+    root["packageDescriptionSummary"] = *packageDescriptionSummary;
   }
 
-  const char* buildConfigCstr = this->Parent->GetOption("CPACK_BUILD_CONFIG");
+  cmValue buildConfigCstr = this->Parent->GetOption("CPACK_BUILD_CONFIG");
   if (buildConfigCstr) {
-    root["buildConfig"] = buildConfigCstr;
+    root["buildConfig"] = *buildConfigCstr;
   }
 
-  const char* defaultDirectoryPermissions =
+  cmValue defaultDirectoryPermissions =
     this->Parent->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
   if (cmNonempty(defaultDirectoryPermissions)) {
-    root["defaultDirectoryPermissions"] = defaultDirectoryPermissions;
+    root["defaultDirectoryPermissions"] = *defaultDirectoryPermissions;
   }
   if (cmIsInternallyOn(this->Parent->GetOption("CPACK_SET_DESTDIR"))) {
     root["setDestdir"] = true;
     root["packagingInstallPrefix"] =
-      this->Parent->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
+      *this->Parent->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
   } else {
     root["setDestdir"] = false;
   }
index b673006..30b6b0d 100644 (file)
@@ -203,11 +203,11 @@ cmGeneratedFileStream& operator<<(cmGeneratedFileStream& s,
 // basically a wrapper that handles the NULL-ptr return from GetOption().
 std::string cmCPackFreeBSDGenerator::var_lookup(const char* var_name)
 {
-  const char* pv = this->GetOption(var_name);
+  cmValue pv = this->GetOption(var_name);
   if (!pv) {
     return std::string();
   }
-  return pv;
+  return *pv;
 }
 
 // Produce UCL in the given @p manifest file for the common
index 00e274d..2f700b4 100644 (file)
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 #include "cmWorkingDirectory.h"
 #include "cmXMLSafe.h"
@@ -78,14 +78,14 @@ int cmCPackGenerator::PrepareNames()
 
   std::string tempDirectory =
     cmStrCat(this->GetOption("CPACK_PACKAGE_DIRECTORY"), "/_CPack_Packages/");
-  const char* toplevelTag = this->GetOption("CPACK_TOPLEVEL_TAG");
+  cmValue toplevelTag = this->GetOption("CPACK_TOPLEVEL_TAG");
   if (toplevelTag) {
-    tempDirectory += toplevelTag;
+    tempDirectory += *toplevelTag;
     tempDirectory += "/";
   }
-  tempDirectory += this->GetOption("CPACK_GENERATOR");
+  tempDirectory += *this->GetOption("CPACK_GENERATOR");
   std::string topDirectory = tempDirectory;
-  const char* pfname = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+  cmValue pfname = this->GetOption("CPACK_PACKAGE_FILE_NAME");
   if (!pfname) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "CPACK_PACKAGE_FILE_NAME not specified" << std::endl);
@@ -99,7 +99,7 @@ int cmCPackGenerator::PrepareNames()
     return 0;
   }
   outName += this->GetOutputExtension();
-  const char* pdir = this->GetOption("CPACK_PACKAGE_DIRECTORY");
+  cmValue pdir = this->GetOption("CPACK_PACKAGE_DIRECTORY");
   if (!pdir) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "CPACK_PACKAGE_DIRECTORY not specified" << std::endl);
@@ -107,25 +107,23 @@ int cmCPackGenerator::PrepareNames()
   }
 
   std::string destFile = pdir;
-  this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PREFIX", destFile.c_str());
+  this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PREFIX", destFile);
   destFile += "/" + outName;
   std::string outFile = topDirectory + "/" + outName;
-  this->SetOptionIfNotSet("CPACK_TOPLEVEL_DIRECTORY", topDirectory.c_str());
-  this->SetOptionIfNotSet("CPACK_TEMPORARY_DIRECTORY", tempDirectory.c_str());
-  this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_NAME", outName.c_str());
-  this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PATH", destFile.c_str());
-  this->SetOptionIfNotSet("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
-                          outFile.c_str());
+  this->SetOptionIfNotSet("CPACK_TOPLEVEL_DIRECTORY", topDirectory);
+  this->SetOptionIfNotSet("CPACK_TEMPORARY_DIRECTORY", tempDirectory);
+  this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_NAME", outName);
+  this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PATH", destFile);
+  this->SetOptionIfNotSet("CPACK_TEMPORARY_PACKAGE_FILE_NAME", outFile);
   this->SetOptionIfNotSet("CPACK_INSTALL_DIRECTORY", this->GetInstallPath());
   this->SetOptionIfNotSet(
     "CPACK_NATIVE_INSTALL_DIRECTORY",
-    cmsys::SystemTools::ConvertToOutputPath(this->GetInstallPath()).c_str());
-  this->SetOptionIfNotSet("CPACK_TEMPORARY_INSTALL_DIRECTORY",
-                          tempDirectory.c_str());
+    cmsys::SystemTools::ConvertToOutputPath(this->GetInstallPath()));
+  this->SetOptionIfNotSet("CPACK_TEMPORARY_INSTALL_DIRECTORY", tempDirectory);
 
   cmCPackLogger(cmCPackLog::LOG_DEBUG,
                 "Look for: CPACK_PACKAGE_DESCRIPTION_FILE" << std::endl);
-  const char* descFileName = this->GetOption("CPACK_PACKAGE_DESCRIPTION_FILE");
+  cmValue descFileName = this->GetOption("CPACK_PACKAGE_DESCRIPTION_FILE");
   if (descFileName && !this->GetOption("CPACK_PACKAGE_DESCRIPTION")) {
     cmCPackLogger(cmCPackLog::LOG_DEBUG,
                   "Look for: " << descFileName << std::endl);
@@ -135,7 +133,7 @@ int cmCPackGenerator::PrepareNames()
                       << descFileName << "]" << std::endl);
       return 0;
     }
-    cmsys::ifstream ifs(descFileName);
+    cmsys::ifstream ifs(descFileName->c_str());
     if (!ifs) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
                     "Cannot open description file name: " << descFileName
@@ -150,10 +148,10 @@ int cmCPackGenerator::PrepareNames()
     while (ifs && cmSystemTools::GetLineFromStream(ifs, line)) {
       ostr << cmXMLSafe(line) << std::endl;
     }
-    this->SetOption("CPACK_PACKAGE_DESCRIPTION", ostr.str().c_str());
-    const char* defFileName =
+    this->SetOption("CPACK_PACKAGE_DESCRIPTION", ostr.str());
+    cmValue defFileName =
       this->GetOption("CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE");
-    if (defFileName && !strcmp(defFileName, descFileName)) {
+    if (defFileName && (defFileName == descFileName)) {
       this->SetOption("CPACK_USED_DEFAULT_PACKAGE_DESCRIPTION_FILE", "ON");
     }
   }
@@ -165,9 +163,9 @@ int cmCPackGenerator::PrepareNames()
         << std::endl);
     return 0;
   }
-  const char* algoSignature = this->GetOption("CPACK_PACKAGE_CHECKSUM");
+  cmValue algoSignature = this->GetOption("CPACK_PACKAGE_CHECKSUM");
   if (algoSignature) {
-    if (!cmCryptoHash::New(algoSignature)) {
+    if (!cmCryptoHash::New(*algoSignature)) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
                     "Cannot recognize algorithm: " << algoSignature
                                                    << std::endl);
@@ -215,7 +213,7 @@ int cmCPackGenerator::InstallProject()
   // prepare default created directory permissions
   mode_t default_dir_mode_v = 0;
   mode_t* default_dir_mode = nullptr;
-  const char* default_dir_install_permissions =
+  cmValue default_dir_install_permissions =
     this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
   if (cmNonempty(default_dir_install_permissions)) {
     std::vector<std::string> items =
@@ -266,7 +264,7 @@ int cmCPackGenerator::InstallProject()
   }
 
   // Run pre-build actions
-  const char* preBuildScripts = this->GetOption("CPACK_PRE_BUILD_SCRIPTS");
+  cmValue preBuildScripts = this->GetOption("CPACK_PRE_BUILD_SCRIPTS");
   if (preBuildScripts) {
     const auto scripts = cmExpandedList(preBuildScripts, false);
     for (const auto& script : scripts) {
@@ -293,7 +291,7 @@ int cmCPackGenerator::InstallProjectViaInstallCommands(
   bool setDestDir, const std::string& tempInstallDirectory)
 {
   (void)setDestDir;
-  const char* installCommands = this->GetOption("CPACK_INSTALL_COMMANDS");
+  cmValue installCommands = this->GetOption("CPACK_INSTALL_COMMANDS");
   if (cmNonempty(installCommands)) {
     std::string tempInstallDirectoryEnv =
       cmStrCat("CMAKE_INSTALL_PREFIX=", tempInstallDirectory);
@@ -333,7 +331,7 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories(
   (void)setDestDir;
   (void)tempInstallDirectory;
   std::vector<cmsys::RegularExpression> ignoreFilesRegex;
-  const char* cpackIgnoreFiles = this->GetOption("CPACK_IGNORE_FILES");
+  cmValue cpackIgnoreFiles = this->GetOption("CPACK_IGNORE_FILES");
   if (cpackIgnoreFiles) {
     std::vector<std::string> ignoreFilesRegexString =
       cmExpandedList(cpackIgnoreFiles);
@@ -343,8 +341,7 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories(
       ignoreFilesRegex.emplace_back(ifr);
     }
   }
-  const char* installDirectories =
-    this->GetOption("CPACK_INSTALLED_DIRECTORIES");
+  cmValue installDirectories = this->GetOption("CPACK_INSTALLED_DIRECTORIES");
   if (cmNonempty(installDirectories)) {
     std::vector<std::string> installDirectoriesVector =
       cmExpandedList(installDirectories);
@@ -472,9 +469,9 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories(
 int cmCPackGenerator::InstallProjectViaInstallScript(
   bool setDestDir, const std::string& tempInstallDirectory)
 {
-  const char* cmakeScripts = this->GetOption("CPACK_INSTALL_SCRIPTS");
+  cmValue cmakeScripts = this->GetOption("CPACK_INSTALL_SCRIPTS");
   {
-    const char* const cmakeScript = this->GetOption("CPACK_INSTALL_SCRIPT");
+    cmValue const cmakeScript = this->GetOption("CPACK_INSTALL_SCRIPT");
     if (cmakeScript && cmakeScripts) {
       cmCPackLogger(
         cmCPackLog::LOG_WARNING,
@@ -485,7 +482,7 @@ int cmCPackGenerator::InstallProjectViaInstallScript(
       cmakeScripts = cmakeScript;
     }
   }
-  if (cmakeScripts && *cmakeScripts) {
+  if (cmakeScripts && !cmakeScripts->empty()) {
     cmCPackLogger(cmCPackLog::LOG_OUTPUT,
                   "- Install scripts: " << cmakeScripts << std::endl);
     std::vector<std::string> cmakeScriptsVector = cmExpandedList(cmakeScripts);
@@ -502,9 +499,9 @@ int cmCPackGenerator::InstallProjectViaInstallScript(
 
         std::string dir;
         if (this->GetOption("CPACK_INSTALL_PREFIX")) {
-          dir += this->GetOption("CPACK_INSTALL_PREFIX");
+          dir += *this->GetOption("CPACK_INSTALL_PREFIX");
         }
-        this->SetOption("CMAKE_INSTALL_PREFIX", dir.c_str());
+        this->SetOption("CMAKE_INSTALL_PREFIX", dir);
         cmCPackLogger(
           cmCPackLog::LOG_DEBUG,
           "- Using DESTDIR + CPACK_INSTALL_PREFIX... (this->SetOption)"
@@ -513,7 +510,7 @@ int cmCPackGenerator::InstallProjectViaInstallScript(
                       "- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'"
                                                             << std::endl);
       } else {
-        this->SetOption("CMAKE_INSTALL_PREFIX", tempInstallDirectory.c_str());
+        this->SetOption("CMAKE_INSTALL_PREFIX", tempInstallDirectory);
 
         cmCPackLogger(cmCPackLog::LOG_DEBUG,
                       "- Using non-DESTDIR install... (this->SetOption)"
@@ -524,9 +521,9 @@ int cmCPackGenerator::InstallProjectViaInstallScript(
       }
 
       this->SetOptionIfNotSet("CMAKE_CURRENT_BINARY_DIR",
-                              tempInstallDirectory.c_str());
+                              tempInstallDirectory);
       this->SetOptionIfNotSet("CMAKE_CURRENT_SOURCE_DIR",
-                              tempInstallDirectory.c_str());
+                              tempInstallDirectory);
       bool res = this->MakefileMap->ReadListFile(installScript);
       if (cmSystemTools::GetErrorOccuredFlag() || !res) {
         return 0;
@@ -540,8 +537,8 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
   bool setDestDir, const std::string& baseTempInstallDirectory,
   const mode_t* default_dir_mode)
 {
-  const char* cmakeProjects = this->GetOption("CPACK_INSTALL_CMAKE_PROJECTS");
-  const char* cmakeGenerator = this->GetOption("CPACK_CMAKE_GENERATOR");
+  cmValue cmakeProjects = this->GetOption("CPACK_INSTALL_CMAKE_PROJECTS");
+  cmValue cmakeGenerator = this->GetOption("CPACK_CMAKE_GENERATOR");
   std::string absoluteDestFiles;
   if (cmNonempty(cmakeProjects)) {
     if (!cmakeGenerator) {
@@ -595,7 +592,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
         // Determine the installation types for this project (if provided).
         std::string installTypesVar = "CPACK_" +
           cmSystemTools::UpperCase(project.Component) + "_INSTALL_TYPES";
-        const char* installTypes = this->GetOption(installTypesVar);
+        cmValue installTypes = this->GetOption(installTypesVar);
         if (cmNonempty(installTypes)) {
           std::vector<std::string> installTypesVector =
             cmExpandedList(installTypes);
@@ -608,7 +605,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
         // Determine the set of components that will be used in this project
         std::string componentsVar =
           "CPACK_COMPONENTS_" + cmSystemTools::UpperCase(project.Component);
-        const char* components = this->GetOption(componentsVar);
+        cmValue components = this->GetOption(componentsVar);
         if (cmNonempty(components)) {
           cmExpandList(components, componentsVector);
           for (std::string const& comp : componentsVector) {
@@ -625,12 +622,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
       std::vector<std::string> buildConfigs;
 
       // Try get configuration names given via `-C` CLI option
-      {
-        const char* const buildConfigCstr =
-          this->GetOption("CPACK_BUILD_CONFIG");
-        auto buildConfig = buildConfigCstr ? buildConfigCstr : std::string{};
-        cmExpandList(buildConfig, buildConfigs);
-      }
+      cmExpandList(this->GetOption("CPACK_BUILD_CONFIG"), buildConfigs);
 
       // Remove duplicates
       std::sort(buildConfigs.begin(), buildConfigs.end());
@@ -682,8 +674,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
       this->CMakeProjects.emplace_back(std::move(project));
     }
   }
-  this->SetOption("CPACK_ABSOLUTE_DESTINATION_FILES",
-                  absoluteDestFiles.c_str());
+  this->SetOption("CPACK_ABSOLUTE_DESTINATION_FILES", absoluteDestFiles);
   return 1;
 }
 
@@ -767,11 +758,11 @@ int cmCPackGenerator::InstallCMakeProject(
     tempInstallDirectory += this->GetComponentInstallDirNameSuffix(component);
     if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
       tempInstallDirectory += "/";
-      tempInstallDirectory += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+      tempInstallDirectory += *this->GetOption("CPACK_PACKAGE_FILE_NAME");
     }
   }
 
-  const char* default_dir_inst_permissions =
+  cmValue default_dir_inst_permissions =
     this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
   if (cmNonempty(default_dir_inst_permissions)) {
     mf.AddDefinition("CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS",
@@ -800,7 +791,7 @@ int cmCPackGenerator::InstallCMakeProject(
     }
     std::string dir;
     if (this->GetOption("CPACK_INSTALL_PREFIX")) {
-      dir += this->GetOption("CPACK_INSTALL_PREFIX");
+      dir += *this->GetOption("CPACK_INSTALL_PREFIX");
     }
     mf.AddDefinition("CMAKE_INSTALL_PREFIX", dir);
 
@@ -924,7 +915,7 @@ int cmCPackGenerator::InstallCMakeProject(
   // forward definition of CMAKE_ABSOLUTE_DESTINATION_FILES
   // to CPack (may be used by generators like CPack RPM or DEB)
   // in order to transparently handle ABSOLUTE PATH
-  if (cmProp def = mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")) {
+  if (cmValue def = mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")) {
     mf.AddDefinition("CPACK_ABSOLUTE_DESTINATION_FILES", *def);
   }
 
@@ -958,7 +949,7 @@ int cmCPackGenerator::InstallCMakeProject(
     }
   }
 
-  if (cmProp d = mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")) {
+  if (cmValue d = mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")) {
     if (!absoluteDestFiles.empty()) {
       absoluteDestFiles += ";";
     }
@@ -975,11 +966,10 @@ int cmCPackGenerator::InstallCMakeProject(
         std::string absoluteDestFilesListComponent =
           cmStrCat(this->GetOption(absoluteDestFileComponent), ';', *d);
         this->SetOption(absoluteDestFileComponent,
-                        absoluteDestFilesListComponent.c_str());
+                        absoluteDestFilesListComponent);
       } else {
-        this->SetOption(
-          absoluteDestFileComponent,
-          cmToCStr(mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")));
+        this->SetOption(absoluteDestFileComponent,
+                        mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES"));
       }
     }
   }
@@ -999,17 +989,29 @@ bool cmCPackGenerator::ReadListFile(const char* moduleName)
   return retval;
 }
 
-void cmCPackGenerator::SetOptionIfNotSet(const std::string& op,
-                                         const char* value)
+template <typename ValueType>
+void cmCPackGenerator::StoreOptionIfNotSet(const std::string& op,
+                                           ValueType value)
 {
-  cmProp def = this->MakefileMap->GetDefinition(op);
+  cmValue def = this->MakefileMap->GetDefinition(op);
   if (cmNonempty(def)) {
     return;
   }
-  this->SetOption(op, value);
+  this->StoreOption(op, value);
 }
 
-void cmCPackGenerator::SetOption(const std::string& op, const char* value)
+void cmCPackGenerator::SetOptionIfNotSet(const std::string& op,
+                                         const char* value)
+{
+  this->StoreOptionIfNotSet(op, value);
+}
+void cmCPackGenerator::SetOptionIfNotSet(const std::string& op, cmValue value)
+{
+  this->StoreOptionIfNotSet(op, value);
+}
+
+template <typename ValueType>
+void cmCPackGenerator::StoreOption(const std::string& op, ValueType value)
 {
   if (!value) {
     this->MakefileMap->RemoveDefinition(op);
@@ -1021,6 +1023,15 @@ void cmCPackGenerator::SetOption(const std::string& op, const char* value)
   this->MakefileMap->AddDefinition(op, value);
 }
 
+void cmCPackGenerator::SetOption(const std::string& op, const char* value)
+{
+  this->StoreOption(op, value);
+}
+void cmCPackGenerator::SetOption(const std::string& op, cmValue value)
+{
+  this->StoreOption(op, value);
+}
+
 int cmCPackGenerator::DoPackage()
 {
   cmCPackLogger(cmCPackLog::LOG_OUTPUT,
@@ -1038,8 +1049,7 @@ int cmCPackGenerator::DoPackage()
   }
 
   if (cmIsOn(this->GetOption("CPACK_REMOVE_TOPLEVEL_DIRECTORY"))) {
-    const char* toplevelDirectory =
-      this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+    cmValue toplevelDirectory = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
     if (cmSystemTools::FileExists(toplevelDirectory)) {
       cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                     "Remove toplevel directory: " << toplevelDirectory
@@ -1060,9 +1070,9 @@ int cmCPackGenerator::DoPackage()
   }
   cmCPackLogger(cmCPackLog::LOG_DEBUG, "Done install project " << std::endl);
 
-  const char* tempPackageFileName =
+  cmValue tempPackageFileName =
     this->GetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME");
-  const char* tempDirectory = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+  cmValue tempDirectory = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
 
   cmCPackLogger(cmCPackLog::LOG_DEBUG, "Find files" << std::endl);
   cmsys::Glob gl;
@@ -1079,7 +1089,7 @@ int cmCPackGenerator::DoPackage()
   cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Create package" << std::endl);
   cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                 "Package files to: "
-                  << (tempPackageFileName ? tempPackageFileName : "(NULL)")
+                  << (tempPackageFileName ? *tempPackageFileName : "(NULL)")
                   << std::endl);
   if (cmSystemTools::FileExists(tempPackageFileName)) {
     cmCPackLogger(cmCPackLog::LOG_VERBOSE,
@@ -1099,9 +1109,8 @@ int cmCPackGenerator::DoPackage()
    * may update this during PackageFiles.
    * (either putting several names or updating the provided one)
    */
-  this->packageFileNames.emplace_back(tempPackageFileName ? tempPackageFileName
-                                                          : "");
-  this->toplevel = tempDirectory;
+  this->packageFileNames.emplace_back(tempPackageFileName);
+  this->toplevel = *tempDirectory;
   { // scope that enables package generators to run internal scripts with
     // latest CMake policies enabled
     cmMakefile::ScopePushPop pp{ this->MakefileMap };
@@ -1115,7 +1124,7 @@ int cmCPackGenerator::DoPackage()
     }
   }
   // Run post-build actions
-  const char* postBuildScripts = this->GetOption("CPACK_POST_BUILD_SCRIPTS");
+  cmValue postBuildScripts = this->GetOption("CPACK_POST_BUILD_SCRIPTS");
   if (postBuildScripts) {
     this->MakefileMap->AddDefinition("CPACK_PACKAGE_FILES",
                                      cmJoin(this->packageFileNames, ";"));
@@ -1135,8 +1144,8 @@ int cmCPackGenerator::DoPackage()
   }
 
   /* Prepare checksum algorithm*/
-  const char* algo = this->GetOption("CPACK_PACKAGE_CHECKSUM");
-  std::unique_ptr<cmCryptoHash> crypto = cmCryptoHash::New(algo ? algo : "");
+  cmValue algo = this->GetOption("CPACK_PACKAGE_CHECKSUM");
+  std::unique_ptr<cmCryptoHash> crypto = cmCryptoHash::New(*algo);
 
   /*
    * Copy the generated packages to final destination
@@ -1151,19 +1160,19 @@ int cmCPackGenerator::DoPackage()
   for (std::string const& pkgFileName : this->packageFileNames) {
     std::string tmpPF(this->GetOption("CPACK_OUTPUT_FILE_PREFIX"));
     std::string filename(cmSystemTools::GetFilenameName(pkgFileName));
-    tempPackageFileName = pkgFileName.c_str();
+    tempPackageFileName = cmValue(pkgFileName);
     tmpPF += "/" + filename;
     const char* packageFileName = tmpPF.c_str();
     cmCPackLogger(cmCPackLog::LOG_DEBUG,
                   "Copy final package(s): "
-                    << (tempPackageFileName ? tempPackageFileName : "(NULL)")
+                    << (tempPackageFileName ? *tempPackageFileName : "(NULL)")
                     << " to " << (packageFileName ? packageFileName : "(NULL)")
                     << std::endl);
     if (!cmSystemTools::CopyFileIfDifferent(pkgFileName, tmpPF)) {
       cmCPackLogger(
         cmCPackLog::LOG_ERROR,
         "Problem copying the package: "
-          << (tempPackageFileName ? tempPackageFileName : "(NULL)") << " to "
+          << (tempPackageFileName ? *tempPackageFileName : "(NULL)") << " to "
           << (packageFileName ? packageFileName : "(NULL)") << std::endl);
       return 0;
     }
@@ -1198,9 +1207,9 @@ int cmCPackGenerator::Initialize(const std::string& name, cmMakefile* mf)
   this->MakefileMap = mf;
   this->Name = name;
   // set the running generator name
-  this->SetOption("CPACK_GENERATOR", this->Name.c_str());
+  this->SetOption("CPACK_GENERATOR", this->Name);
   // Load the project specific config file
-  const char* config = this->GetOption("CPACK_PROJECT_CONFIG_FILE");
+  cmValue config = this->GetOption("CPACK_PROJECT_CONFIG_FILE");
   if (config) {
     mf->ReadListFile(config);
   }
@@ -1234,7 +1243,7 @@ bool cmCPackGenerator::IsOn(const std::string& name) const
 
 bool cmCPackGenerator::IsSetToOff(const std::string& op) const
 {
-  cmProp ret = this->MakefileMap->GetDefinition(op);
+  cmValue ret = this->MakefileMap->GetDefinition(op);
   if (cmNonempty(ret)) {
     return cmIsOff(*ret);
   }
@@ -1243,22 +1252,21 @@ bool cmCPackGenerator::IsSetToOff(const std::string& op) const
 
 bool cmCPackGenerator::IsSetToEmpty(const std::string& op) const
 {
-  cmProp ret = this->MakefileMap->GetDefinition(op);
+  cmValue ret = this->MakefileMap->GetDefinition(op);
   if (ret) {
     return ret->empty();
   }
   return false;
 }
 
-const char* cmCPackGenerator::GetOption(const std::string& op) const
+cmValue cmCPackGenerator::GetOption(const std::string& op) const
 {
-  cmProp ret = this->MakefileMap->GetDefinition(op);
+  cmValue ret = this->MakefileMap->GetDefinition(op);
   if (!ret) {
     cmCPackLogger(cmCPackLog::LOG_DEBUG,
                   "Warning, GetOption return NULL for: " << op << std::endl);
-    return nullptr;
   }
-  return ret->c_str();
+  return ret;
 }
 
 std::vector<std::string> cmCPackGenerator::GetOptions() const
@@ -1311,7 +1319,7 @@ const char* cmCPackGenerator::GetPackagingInstallPrefix()
                   << this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX") << "'"
                   << std::endl);
 
-  return this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
+  return this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX")->c_str();
 }
 
 std::string cmCPackGenerator::FindTemplate(const char* name)
@@ -1391,12 +1399,8 @@ int cmCPackGenerator::PrepareGroupingKind()
     method = ONE_PACKAGE_PER_GROUP;
   }
 
-  std::string groupingType;
-
   // Second way to specify grouping
-  if (nullptr != this->GetOption("CPACK_COMPONENTS_GROUPING")) {
-    groupingType = this->GetOption("CPACK_COMPONENTS_GROUPING");
-  }
+  std::string groupingType = *this->GetOption("CPACK_COMPONENTS_GROUPING");
 
   if (!groupingType.empty()) {
     cmCPackLogger(cmCPackLog::LOG_VERBOSE,
@@ -1477,18 +1481,18 @@ std::string cmCPackGenerator::GetComponentPackageFileName(
     if (isGroupName) {
       std::string groupDispVar = "CPACK_COMPONENT_GROUP_" +
         cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME";
-      const char* groupDispName = this->GetOption(groupDispVar);
+      cmValue groupDispName = this->GetOption(groupDispVar);
       if (groupDispName) {
-        suffix = "-" + std::string(groupDispName);
+        suffix = "-" + *groupDispName;
       }
     }
     /* the [single] component case */
     else {
       std::string dispVar = "CPACK_COMPONENT_" +
         cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME";
-      const char* dispName = this->GetOption(dispVar);
+      cmValue dispName = this->GetOption(dispVar);
       if (dispName) {
-        suffix = "-" + std::string(dispName);
+        suffix = "-" + *dispName;
       }
     }
   }
@@ -1531,9 +1535,9 @@ cmCPackInstallationType* cmCPackGenerator::GetInstallationType(
       "CPACK_INSTALL_TYPE_" + cmsys::SystemTools::UpperCase(name);
     installType->Name = name;
 
-    const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
+    cmValue displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
     if (cmNonempty(displayName)) {
-      installType->DisplayName = displayName;
+      installType->DisplayName = *displayName;
     } else {
       installType->DisplayName = installType->Name;
     }
@@ -1553,9 +1557,9 @@ cmCPackComponent* cmCPackGenerator::GetComponent(
     std::string macroPrefix =
       "CPACK_COMPONENT_" + cmsys::SystemTools::UpperCase(name);
     component->Name = name;
-    const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
+    cmValue displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
     if (cmNonempty(displayName)) {
-      component->DisplayName = displayName;
+      component->DisplayName = *displayName;
     } else {
       component->DisplayName = component->Name;
     }
@@ -1565,17 +1569,17 @@ cmCPackComponent* cmCPackGenerator::GetComponent(
     component->IsDownloaded = this->IsOn(macroPrefix + "_DOWNLOADED") ||
       cmIsOn(this->GetOption("CPACK_DOWNLOAD_ALL"));
 
-    const char* archiveFile = this->GetOption(macroPrefix + "_ARCHIVE_FILE");
+    cmValue archiveFile = this->GetOption(macroPrefix + "_ARCHIVE_FILE");
     if (cmNonempty(archiveFile)) {
-      component->ArchiveFile = archiveFile;
+      component->ArchiveFile = *archiveFile;
     }
 
-    const char* plist = this->GetOption(macroPrefix + "_PLIST");
+    cmValue plist = this->GetOption(macroPrefix + "_PLIST");
     if (cmNonempty(plist)) {
-      component->Plist = plist;
+      component->Plist = *plist;
     }
 
-    const char* groupName = this->GetOption(macroPrefix + "_GROUP");
+    cmValue groupName = this->GetOption(macroPrefix + "_GROUP");
     if (cmNonempty(groupName)) {
       component->Group = this->GetComponentGroup(projectName, groupName);
       component->Group->Components.push_back(component);
@@ -1583,13 +1587,13 @@ cmCPackComponent* cmCPackGenerator::GetComponent(
       component->Group = nullptr;
     }
 
-    const char* description = this->GetOption(macroPrefix + "_DESCRIPTION");
+    cmValue description = this->GetOption(macroPrefix + "_DESCRIPTION");
     if (cmNonempty(description)) {
-      component->Description = description;
+      component->Description = *description;
     }
 
     // Determine the installation types.
-    const char* installTypes = this->GetOption(macroPrefix + "_INSTALL_TYPES");
+    cmValue installTypes = this->GetOption(macroPrefix + "_INSTALL_TYPES");
     if (cmNonempty(installTypes)) {
       std::vector<std::string> installTypesVector =
         cmExpandedList(installTypes);
@@ -1600,7 +1604,7 @@ cmCPackComponent* cmCPackGenerator::GetComponent(
     }
 
     // Determine the component dependencies.
-    const char* depends = this->GetOption(macroPrefix + "_DEPENDS");
+    cmValue depends = this->GetOption(macroPrefix + "_DEPENDS");
     if (cmNonempty(depends)) {
       std::vector<std::string> dependsVector = cmExpandedList(depends);
       for (std::string const& depend : dependsVector) {
@@ -1624,21 +1628,20 @@ cmCPackComponentGroup* cmCPackGenerator::GetComponentGroup(
   if (!hasGroup) {
     // Define the group
     group->Name = name;
-    const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
+    cmValue displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME");
     if (cmNonempty(displayName)) {
-      group->DisplayName = displayName;
+      group->DisplayName = *displayName;
     } else {
       group->DisplayName = group->Name;
     }
 
-    const char* description = this->GetOption(macroPrefix + "_DESCRIPTION");
+    cmValue description = this->GetOption(macroPrefix + "_DESCRIPTION");
     if (cmNonempty(description)) {
-      group->Description = description;
+      group->Description = *description;
     }
     group->IsBold = this->IsOn(macroPrefix + "_BOLD_TITLE");
     group->IsExpandedByDefault = this->IsOn(macroPrefix + "_EXPANDED");
-    const char* parentGroupName =
-      this->GetOption(macroPrefix + "_PARENT_GROUP");
+    cmValue parentGroupName = this->GetOption(macroPrefix + "_PARENT_GROUP");
     if (cmNonempty(parentGroupName)) {
       group->ParentGroup =
         this->GetComponentGroup(projectName, parentGroupName);
index 2512d42..65156ab 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "cmCPackComponentGroup.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 class cmCPackLog;
 class cmGlobalGenerator;
@@ -84,8 +85,18 @@ public:
 
   //! Set and get the options
   void SetOption(const std::string& op, const char* value);
+  void SetOption(const std::string& op, const std::string& value)
+  {
+    this->SetOption(op, cmValue(value));
+  }
+  void SetOption(const std::string& op, cmValue value);
   void SetOptionIfNotSet(const std::string& op, const char* value);
-  const char* GetOption(const std::string& op) const;
+  void SetOptionIfNotSet(const std::string& op, const std::string& value)
+  {
+    this->SetOptionIfNotSet(op, cmValue(value));
+  }
+  void SetOptionIfNotSet(const std::string& op, cmValue value);
+  cmValue GetOption(const std::string& op) const;
   std::vector<std::string> GetOptions() const;
   bool IsSet(const std::string& name) const;
   bool IsOn(const std::string& name) const;
@@ -323,6 +334,12 @@ protected:
   bool TraceExpand;
 
   cmMakefile* MakefileMap;
+
+private:
+  template <typename ValueType>
+  void StoreOption(const std::string& op, ValueType value);
+  template <typename ValueType>
+  void StoreOptionIfNotSet(const std::string& op, ValueType value);
 };
 
 #define cmCPackTypeMacro(klass, superclass)                                   \
index 6bd0d1b..ecc5e08 100644 (file)
@@ -21,6 +21,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 /* NSIS uses different command line syntax on Windows and others */
 #ifdef _WIN32
@@ -84,7 +85,7 @@ int cmCPackNSISGenerator::PackageFiles()
   }
   cmCPackLogger(cmCPackLog::LOG_DEBUG,
                 "Uninstall Files: " << str.str() << std::endl);
-  this->SetOptionIfNotSet("CPACK_NSIS_DELETE_FILES", str.str().c_str());
+  this->SetOptionIfNotSet("CPACK_NSIS_DELETE_FILES", str.str());
   std::vector<std::string> dirs;
   this->GetListOfSubdirectories(this->toplevel.c_str(), dirs);
   std::ostringstream dstr;
@@ -120,7 +121,7 @@ int cmCPackNSISGenerator::PackageFiles()
   }
   cmCPackLogger(cmCPackLog::LOG_DEBUG,
                 "Uninstall Dirs: " << dstr.str() << std::endl);
-  this->SetOptionIfNotSet("CPACK_NSIS_DELETE_DIRECTORIES", dstr.str().c_str());
+  this->SetOptionIfNotSet("CPACK_NSIS_DELETE_DIRECTORIES", dstr.str());
 
   cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                 "Configure file: " << nsisInFileName << " to " << nsisFileName
@@ -142,15 +143,15 @@ int cmCPackNSISGenerator::PackageFiles()
   }
   std::string installerHeaderImage;
   if (this->IsSet("CPACK_NSIS_MUI_HEADERIMAGE")) {
-    installerHeaderImage = this->GetOption("CPACK_NSIS_MUI_HEADERIMAGE");
+    installerHeaderImage = *this->GetOption("CPACK_NSIS_MUI_HEADERIMAGE");
   } else if (this->IsSet("CPACK_PACKAGE_ICON")) {
-    installerHeaderImage = this->GetOption("CPACK_PACKAGE_ICON");
+    installerHeaderImage = *this->GetOption("CPACK_PACKAGE_ICON");
   }
   if (!installerHeaderImage.empty()) {
     std::string installerIconCode = cmStrCat(
       "!define MUI_HEADERIMAGE_BITMAP \"", installerHeaderImage, "\"\n");
     this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_ICON_CODE",
-                            installerIconCode.c_str());
+                            installerIconCode);
   }
 
   if (this->IsSet("CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP")) {
@@ -158,7 +159,7 @@ int cmCPackNSISGenerator::PackageFiles()
       "!define MUI_WELCOMEFINISHPAGE_BITMAP \"",
       this->GetOption("CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP"), "\"\n");
     this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_WELCOMEFINISH_CODE",
-                            installerBitmapCode.c_str());
+                            installerBitmapCode);
   }
 
   if (this->IsSet("CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP")) {
@@ -166,7 +167,7 @@ int cmCPackNSISGenerator::PackageFiles()
       "!define MUI_UNWELCOMEFINISHPAGE_BITMAP \"",
       this->GetOption("CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP"), "\"\n");
     this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_UNWELCOMEFINISH_CODE",
-                            installerBitmapCode.c_str());
+                            installerBitmapCode);
   }
 
   if (this->IsSet("CPACK_NSIS_MUI_FINISHPAGE_RUN")) {
@@ -175,7 +176,7 @@ int cmCPackNSISGenerator::PackageFiles()
                this->GetOption("CPACK_NSIS_EXECUTABLES_DIRECTORY"), '\\',
                this->GetOption("CPACK_NSIS_MUI_FINISHPAGE_RUN"), "\"\n");
     this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE",
-                            installerRunCode.c_str());
+                            installerRunCode);
   }
 
   if (this->IsSet("CPACK_NSIS_WELCOME_TITLE")) {
@@ -183,7 +184,7 @@ int cmCPackNSISGenerator::PackageFiles()
       cmStrCat("!define MUI_WELCOMEPAGE_TITLE \"",
                this->GetOption("CPACK_NSIS_WELCOME_TITLE"), "\"");
     this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_WELCOME_TITLE_CODE",
-                            welcomeTitleCode.c_str());
+                            welcomeTitleCode);
   }
 
   if (this->IsSet("CPACK_NSIS_WELCOME_TITLE_3LINES")) {
@@ -196,7 +197,7 @@ int cmCPackNSISGenerator::PackageFiles()
       cmStrCat("!define MUI_FINISHPAGE_TITLE \"",
                this->GetOption("CPACK_NSIS_FINISH_TITLE"), "\"");
     this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_FINISH_TITLE_CODE",
-                            finishTitleCode.c_str());
+                            finishTitleCode);
   }
 
   if (this->IsSet("CPACK_NSIS_FINISH_TITLE_3LINES")) {
@@ -231,8 +232,14 @@ int cmCPackNSISGenerator::PackageFiles()
     std::string brandingTextCode =
       cmStrCat("BrandingText /TRIM", brandingTextPosition, " \"",
                this->GetOption("CPACK_NSIS_BRANDING_TEXT"), "\"\n");
-    this->SetOptionIfNotSet("CPACK_NSIS_BRANDING_TEXT_CODE",
-                            brandingTextCode.c_str());
+    this->SetOptionIfNotSet("CPACK_NSIS_BRANDING_TEXT_CODE", brandingTextCode);
+  }
+
+  if (!this->IsSet("CPACK_NSIS_IGNORE_LICENSE_PAGE")) {
+    std::string licenceCode =
+      cmStrCat("!insertmacro MUI_PAGE_LICENSE \"",
+               this->GetOption("CPACK_RESOURCE_FILE_LICENSE"), "\"\n");
+    this->SetOptionIfNotSet("CPACK_NSIS_LICENSE_PAGE", licenceCode);
   }
 
   // Setup all of the component sections
@@ -327,7 +334,7 @@ int cmCPackNSISGenerator::PackageFiles()
         componentDescriptions + groupDescriptions +
         "!insertmacro MUI_FUNCTION_DESCRIPTION_END\n";
       this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC",
-                              componentDescriptions.c_str());
+                              componentDescriptions);
     }
 
     if (anyDownloadedComponents) {
@@ -337,18 +344,15 @@ int cmCPackNSISGenerator::PackageFiles()
       }
     }
 
-    this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES",
-                            installTypesCode.c_str());
+    this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES", installTypesCode);
     this->SetOptionIfNotSet("CPACK_NSIS_PAGE_COMPONENTS",
                             "!insertmacro MUI_PAGE_COMPONENTS");
     this->SetOptionIfNotSet("CPACK_NSIS_FULL_INSTALL", "");
-    this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTIONS",
-                            componentCode.c_str());
-    this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTION_LIST",
-                            sectionList.c_str());
+    this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTIONS", componentCode);
+    this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTION_LIST", sectionList);
     this->SetOptionIfNotSet("CPACK_NSIS_SECTION_SELECTED_VARS",
-                            selectedVarsList.c_str());
-    this->SetOption("CPACK_NSIS_DEFINES", defines.c_str());
+                            selectedVarsList);
+    this->SetOption("CPACK_NSIS_DEFINES", defines);
   }
 
   this->ConfigureFile(nsisInInstallOptions, nsisInstallOptions);
@@ -472,8 +476,8 @@ int cmCPackNSISGenerator::InitializeInternal()
   cmsys::RegularExpression versionRexCVS("v(.*)\\.cvs");
   if (!resS || retVal ||
       (!versionRex.find(output) && !versionRexCVS.find(output))) {
-    const char* topDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
-    std::string tmpFile = cmStrCat(topDir ? topDir : ".", "/NSISOutput.log");
+    cmValue topDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+    std::string tmpFile = cmStrCat(topDir ? *topDir : ".", "/NSISOutput.log");
     cmGeneratedFileStream ofs(tmpFile);
     ofs << "# Run command: " << nsisCmd << std::endl
         << "# Output:" << std::endl
@@ -487,12 +491,12 @@ int cmCPackNSISGenerator::InitializeInternal()
   }
   if (versionRex.find(output)) {
     double nsisVersion = atof(versionRex.match(1).c_str());
-    double minNSISVersion = 3.0;
+    double minNSISVersion = 3.03;
     cmCPackLogger(cmCPackLog::LOG_DEBUG,
                   "NSIS Version: " << nsisVersion << std::endl);
     if (nsisVersion < minNSISVersion) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
-                    "CPack requires NSIS Version 3.0 or greater.  "
+                    "CPack requires NSIS Version 3.03 or greater. "
                     "NSIS found on the system was: "
                       << nsisVersion << std::endl);
       return 0;
@@ -503,13 +507,13 @@ int cmCPackNSISGenerator::InitializeInternal()
     cmCPackLogger(cmCPackLog::LOG_DEBUG,
                   "NSIS Version: CVS " << versionRexCVS.match(1) << std::endl);
   }
-  this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", nsisPath.c_str());
+  this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", nsisPath);
   this->SetOptionIfNotSet("CPACK_NSIS_EXECUTABLES_DIRECTORY", "bin");
-  const char* cpackPackageExecutables =
+  cmValue cpackPackageExecutables =
     this->GetOption("CPACK_PACKAGE_EXECUTABLES");
-  const char* cpackPackageDeskTopLinks =
+  cmValue cpackPackageDeskTopLinks =
     this->GetOption("CPACK_CREATE_DESKTOP_LINKS");
-  const char* cpackNsisExecutablesDirectory =
+  cmValue cpackNsisExecutablesDirectory =
     this->GetOption("CPACK_NSIS_EXECUTABLES_DIRECTORY");
   std::vector<std::string> cpackPackageDesktopLinksVector;
   if (cpackPackageDeskTopLinks) {
@@ -571,8 +575,8 @@ int cmCPackNSISGenerator::InitializeInternal()
   }
 
   this->CreateMenuLinks(str, deleteStr);
-  this->SetOptionIfNotSet("CPACK_NSIS_CREATE_ICONS", str.str().c_str());
-  this->SetOptionIfNotSet("CPACK_NSIS_DELETE_ICONS", deleteStr.str().c_str());
+  this->SetOptionIfNotSet("CPACK_NSIS_CREATE_ICONS", str.str());
+  this->SetOptionIfNotSet("CPACK_NSIS_DELETE_ICONS", deleteStr.str());
 
   this->SetOptionIfNotSet("CPACK_NSIS_COMPRESSOR", "lzma");
 
@@ -582,7 +586,7 @@ int cmCPackNSISGenerator::InitializeInternal()
 void cmCPackNSISGenerator::CreateMenuLinks(std::ostream& str,
                                            std::ostream& deleteStr)
 {
-  const char* cpackMenuLinks = this->GetOption("CPACK_NSIS_MENU_LINKS");
+  cmValue cpackMenuLinks = this->GetOption("CPACK_NSIS_MENU_LINKS");
   if (!cpackMenuLinks) {
     return;
   }
@@ -721,11 +725,10 @@ std::string cmCPackNSISGenerator::CreateComponentDescription(
     }
 
     // Create the directory for the upload area
-    const char* userUploadDirectory =
-      this->GetOption("CPACK_UPLOAD_DIRECTORY");
+    cmValue userUploadDirectory = this->GetOption("CPACK_UPLOAD_DIRECTORY");
     std::string uploadDirectory;
     if (cmNonempty(userUploadDirectory)) {
-      uploadDirectory = userUploadDirectory;
+      uploadDirectory = *userUploadDirectory;
     } else {
       uploadDirectory =
         cmStrCat(this->GetOption("CPACK_PACKAGE_DIRECTORY"), "/CPackUploads");
@@ -961,9 +964,9 @@ std::string cmCPackNSISGenerator::CreateComponentGroupDescription(
 std::string cmCPackNSISGenerator::CustomComponentInstallDirectory(
   cm::string_view componentName)
 {
-  const char* outputDir = this->GetOption(
+  cmValue outputDir = this->GetOption(
     cmStrCat("CPACK_NSIS_", componentName, "_INSTALL_DIRECTORY"));
-  return outputDir ? outputDir : "$INSTDIR";
+  return outputDir ? *outputDir : "$INSTDIR";
 }
 
 std::string cmCPackNSISGenerator::TranslateNewlines(std::string str)
index 98dc890..5de8179 100644 (file)
@@ -14,6 +14,7 @@
 #include "cmCPackLog.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 bool cmCPackNuGetGenerator::SupportsComponentInstallation() const
 {
@@ -81,10 +82,10 @@ void cmCPackNuGetGenerator::SetupGroupComponentVariables(bool ignoreGroup)
                      std::back_inserter(components),
                      [](cmCPackComponent const* comp) { return comp->Name; });
       this->SetOption("CPACK_NUGET_" + compGUp + "_GROUP_COMPONENTS",
-                      cmJoin(components, ";").c_str());
+                      cmJoin(components, ";"));
     }
     if (!groups.empty()) {
-      this->SetOption("CPACK_NUGET_GROUPS", cmJoin(groups, ";").c_str());
+      this->SetOption("CPACK_NUGET_GROUPS", cmJoin(groups, ";"));
     }
 
     // Handle Orphan components (components not belonging to any groups)
@@ -102,8 +103,7 @@ void cmCPackNuGetGenerator::SetupGroupComponentVariables(bool ignoreGroup)
       }
     }
     if (!components.empty()) {
-      this->SetOption("CPACK_NUGET_COMPONENTS",
-                      cmJoin(components, ";").c_str());
+      this->SetOption("CPACK_NUGET_COMPONENTS", cmJoin(components, ";"));
     }
 
   } else {
@@ -114,13 +114,13 @@ void cmCPackNuGetGenerator::SetupGroupComponentVariables(bool ignoreGroup)
                    [](std::pair<std::string, cmCPackComponent> const& comp) {
                      return comp.first;
                    });
-    this->SetOption("CPACK_NUGET_COMPONENTS", cmJoin(components, ";").c_str());
+    this->SetOption("CPACK_NUGET_COMPONENTS", cmJoin(components, ";"));
   }
 }
 
 void cmCPackNuGetGenerator::AddGeneratedPackageNames()
 {
-  const char* const files_list = this->GetOption("GEN_CPACK_OUTPUT_FILES");
+  cmValue const files_list = this->GetOption("GEN_CPACK_OUTPUT_FILES");
   if (!files_list) {
     cmCPackLogger(
       cmCPackLog::LOG_ERROR,
@@ -129,7 +129,7 @@ void cmCPackNuGetGenerator::AddGeneratedPackageNames()
     return;
   }
   // add the generated packages to package file names list
-  std::string fileNames{ files_list };
+  const std::string& fileNames = *files_list;
   const char sep = ';';
   std::string::size_type pos1 = 0;
   std::string::size_type pos2 = fileNames.find(sep, pos1 + 1);
index 5de4a6f..7bf1dc7 100644 (file)
@@ -12,6 +12,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmCPackOSXX11Generator::cmCPackOSXX11Generator() = default;
 
@@ -22,7 +23,7 @@ int cmCPackOSXX11Generator::PackageFiles()
   // TODO: Use toplevel ?
   //       It is used! Is this an obsolete comment?
 
-  const char* cpackPackageExecutables =
+  cmValue cpackPackageExecutables =
     this->GetOption("CPACK_PACKAGE_EXECUTABLES");
   if (cpackPackageExecutables) {
     cmCPackLogger(cmCPackLog::LOG_DEBUG,
@@ -45,8 +46,7 @@ int cmCPackOSXX11Generator::PackageFiles()
          it != cpackPackageExecutablesVector.end(); ++it) {
       std::string cpackExecutableName = *it;
       ++it;
-      this->SetOptionIfNotSet("CPACK_EXECUTABLE_NAME",
-                              cpackExecutableName.c_str());
+      this->SetOptionIfNotSet("CPACK_EXECUTABLE_NAME", cpackExecutableName);
     }
   }
 
@@ -70,7 +70,7 @@ int cmCPackOSXX11Generator::PackageFiles()
   const char* scrDir = scriptDirectory.c_str();
   const char* contDir = contentsDirectory.c_str();
   const char* rsrcFile = resourceFileName.c_str();
-  const char* iconFile = this->GetOption("CPACK_PACKAGE_ICON");
+  cmValue iconFile = this->GetOption("CPACK_PACKAGE_ICON");
   if (iconFile) {
     std::string iconFileName = cmsys::SystemTools::GetFilenameName(iconFile);
     if (!cmSystemTools::FileExists(iconFile)) {
@@ -83,7 +83,7 @@ int cmCPackOSXX11Generator::PackageFiles()
     }
     std::string destFileName = resourcesDirectory + "/" + iconFileName;
     this->ConfigureFile(iconFile, destFileName, true);
-    this->SetOptionIfNotSet("CPACK_APPLE_GUI_ICON", iconFileName.c_str());
+    this->SetOptionIfNotSet("CPACK_APPLE_GUI_ICON", iconFileName);
   }
 
   std::string applicationsLinkName = diskImageDirectory + "/Applications";
@@ -103,9 +103,9 @@ int cmCPackOSXX11Generator::PackageFiles()
                                    true) ||
       !this->CopyResourcePlistFile("OSXScriptLauncher.rsrc", dir, rsrcFile,
                                    true) ||
-      !this->CopyResourcePlistFile("OSXScriptLauncher", appdir,
-                                   this->GetOption("CPACK_PACKAGE_FILE_NAME"),
-                                   true)) {
+      !this->CopyResourcePlistFile(
+        "OSXScriptLauncher", appdir,
+        this->GetOption("CPACK_PACKAGE_FILE_NAME").GetCStr(), true)) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Problem copying the resource files" << std::endl);
     return 0;
@@ -190,8 +190,7 @@ int cmCPackOSXX11Generator::InitializeInternal()
                   "Cannot find hdiutil compiler" << std::endl);
     return 0;
   }
-  this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE",
-                          pkgPath.c_str());
+  this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE", pkgPath);
 
   return this->Superclass::InitializeInternal();
 }
index ac3d64d..91adf32 100644 (file)
@@ -9,6 +9,7 @@
 #include "cmCPackLog.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmXMLWriter.h"
 
 cmCPackPKGGenerator::cmCPackPKGGenerator()
@@ -56,7 +57,7 @@ void cmCPackPKGGenerator::CreateBackground(const char* themeName,
   std::string opt = (themeName == nullptr)
     ? cmStrCat("CPACK_", genName, "_BACKGROUND")
     : cmStrCat("CPACK_", genName, "_BACKGROUND_", paramSuffix);
-  const char* bgFileName = this->GetOption(opt);
+  cmValue bgFileName = this->GetOption(opt);
   if (bgFileName == nullptr) {
     return;
   }
@@ -78,7 +79,7 @@ void cmCPackPKGGenerator::CreateBackground(const char* themeName,
 
   xout.Attribute("file", bgFileName);
 
-  const char* param = this->GetOption(cmStrCat(opt, "_ALIGNMENT"));
+  cmValue param = this->GetOption(cmStrCat(opt, "_ALIGNMENT"));
   if (param != nullptr) {
     xout.Attribute("alignment", param);
   }
@@ -166,7 +167,7 @@ void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile,
   // Dark Aqua
   this->CreateBackground("darkAqua", metapackageFile, genName, xout);
 
-  this->SetOption("CPACK_PACKAGEMAKER_CHOICES", choiceOut.str().c_str());
+  this->SetOption("CPACK_PACKAGEMAKER_CHOICES", choiceOut.str());
 
   // Create the distribution.dist file in the metapackage to turn it
   // into a distribution package.
@@ -315,7 +316,7 @@ bool cmCPackPKGGenerator::CopyCreateResourceFile(const std::string& name,
 {
   std::string uname = cmSystemTools::UpperCase(name);
   std::string cpackVar = "CPACK_RESOURCE_FILE_" + uname;
-  const char* inFileName = this->GetOption(cpackVar);
+  cmValue inFileName = this->GetOption(cpackVar);
   if (!inFileName) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "CPack option: " << cpackVar.c_str()
@@ -347,11 +348,10 @@ bool cmCPackPKGGenerator::CopyCreateResourceFile(const std::string& name,
 
   // Set this so that distribution.dist gets the right name (without
   // the path).
-  this->SetOption("CPACK_RESOURCE_FILE_" + uname + "_NOPATH",
-                  (name + ext).c_str());
+  this->SetOption("CPACK_RESOURCE_FILE_" + uname + "_NOPATH", (name + ext));
 
   cmCPackLogger(cmCPackLog::LOG_VERBOSE,
-                "Configure file: " << (inFileName ? inFileName : "(NULL)")
+                "Configure file: " << (inFileName ? *inFileName : "(NULL)")
                                    << " to " << destFileName << std::endl);
   this->ConfigureFile(inFileName, destFileName);
   return true;
index f51ea42..a8cf1fa 100644 (file)
@@ -18,6 +18,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmXMLWriter.h"
 
 static inline unsigned int getVersion(unsigned int major, unsigned int minor)
@@ -79,9 +80,9 @@ int cmCPackPackageMakerGenerator::PackageFiles()
     resDir += "/en.lproj";
   }
 
-  const char* preflight = this->GetOption("CPACK_PREFLIGHT_SCRIPT");
-  const char* postflight = this->GetOption("CPACK_POSTFLIGHT_SCRIPT");
-  const char* postupgrade = this->GetOption("CPACK_POSTUPGRADE_SCRIPT");
+  cmValue preflight = this->GetOption("CPACK_PREFLIGHT_SCRIPT");
+  cmValue postflight = this->GetOption("CPACK_POSTFLIGHT_SCRIPT");
+  cmValue postupgrade = this->GetOption("CPACK_POSTUPGRADE_SCRIPT");
 
   if (this->Components.empty()) {
     // Create directory structure
@@ -167,10 +168,9 @@ int cmCPackPackageMakerGenerator::PackageFiles()
 
     // Create the directory where downloaded component packages will
     // be placed.
-    const char* userUploadDirectory =
-      this->GetOption("CPACK_UPLOAD_DIRECTORY");
+    cmValue userUploadDirectory = this->GetOption("CPACK_UPLOAD_DIRECTORY");
     std::string uploadDirectory;
-    if (userUploadDirectory && *userUploadDirectory) {
+    if (userUploadDirectory && !userUploadDirectory->empty()) {
       uploadDirectory = userUploadDirectory;
     } else {
       uploadDirectory =
@@ -352,8 +352,8 @@ int cmCPackPackageMakerGenerator::InitializeInternal()
                      "/PackageMaker.app/Contents/MacOS");
 
   std::string pkgPath;
-  const char* inst_program = this->GetOption("CPACK_INSTALLER_PROGRAM");
-  if (inst_program && *inst_program) {
+  cmValue inst_program = this->GetOption("CPACK_INSTALLER_PROGRAM");
+  if (inst_program && !inst_program->empty()) {
     pkgPath = inst_program;
   } else {
     pkgPath = cmSystemTools::FindProgram("PackageMaker", paths, false);
@@ -362,7 +362,7 @@ int cmCPackPackageMakerGenerator::InitializeInternal()
                     "Cannot find PackageMaker compiler" << std::endl);
       return 0;
     }
-    this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", pkgPath.c_str());
+    this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", pkgPath);
   }
 
   // Get path to the real PackageMaker, not a symlink:
@@ -427,11 +427,12 @@ int cmCPackPackageMakerGenerator::InitializeInternal()
   // Determine the package compatibility version. If it wasn't
   // specified by the user, we define it based on which features the
   // user requested.
-  const char* packageCompat = this->GetOption("CPACK_OSX_PACKAGE_VERSION");
-  if (packageCompat && *packageCompat) {
+  cmValue packageCompat = this->GetOption("CPACK_OSX_PACKAGE_VERSION");
+  if (packageCompat && !packageCompat->empty()) {
     unsigned int majorVersion = 10;
     unsigned int minorVersion = 5;
-    int res = sscanf(packageCompat, "%u.%u", &majorVersion, &minorVersion);
+    int res =
+      sscanf(packageCompat->c_str(), "%u.%u", &majorVersion, &minorVersion);
     if (res == 2) {
       this->PackageCompatibilityVersion =
         getVersion(majorVersion, minorVersion);
@@ -454,8 +455,7 @@ int cmCPackPackageMakerGenerator::InitializeInternal()
                   "Cannot find hdiutil compiler" << std::endl);
     return 0;
   }
-  this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE",
-                          pkgPath.c_str());
+  this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE", pkgPath);
 
   return this->Superclass::InitializeInternal();
 }
@@ -543,8 +543,7 @@ bool cmCPackPackageMakerGenerator::GenerateComponentPackage(
 
     // Create the Info.plist file for this component
     std::string moduleVersionSuffix = cmStrCat('.', component.Name);
-    this->SetOption("CPACK_MODULE_VERSION_SUFFIX",
-                    moduleVersionSuffix.c_str());
+    this->SetOption("CPACK_MODULE_VERSION_SUFFIX", moduleVersionSuffix);
     std::string infoFileName = cmStrCat(component.Name, "-Info.plist");
     if (!this->CopyResourcePlistFile("Info.plist", infoFileName.c_str())) {
       return false;
index a3e55de..f55b8de 100644 (file)
@@ -12,6 +12,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmCPackProductBuildGenerator::cmCPackProductBuildGenerator()
 {
@@ -87,11 +88,11 @@ int cmCPackProductBuildGenerator::PackageFiles()
   std::string version = this->GetOption("CPACK_PACKAGE_VERSION");
   std::string productbuild = this->GetOption("CPACK_COMMAND_PRODUCTBUILD");
   std::string identityName;
-  if (const char* n = this->GetOption("CPACK_PRODUCTBUILD_IDENTITY_NAME")) {
+  if (cmValue n = this->GetOption("CPACK_PRODUCTBUILD_IDENTITY_NAME")) {
     identityName = n;
   }
   std::string keychainPath;
-  if (const char* p = this->GetOption("CPACK_PRODUCTBUILD_KEYCHAIN_PATH")) {
+  if (cmValue p = this->GetOption("CPACK_PRODUCTBUILD_KEYCHAIN_PATH")) {
     keychainPath = p;
   }
 
@@ -122,7 +123,7 @@ int cmCPackProductBuildGenerator::InitializeInternal()
                   "Cannot find pkgbuild executable" << std::endl);
     return 0;
   }
-  this->SetOptionIfNotSet("CPACK_COMMAND_PKGBUILD", program.c_str());
+  this->SetOptionIfNotSet("CPACK_COMMAND_PKGBUILD", program);
 
   program = cmSystemTools::FindProgram("productbuild", no_paths, false);
   if (program.empty()) {
@@ -130,7 +131,7 @@ int cmCPackProductBuildGenerator::InitializeInternal()
                   "Cannot find productbuild executable" << std::endl);
     return 0;
   }
-  this->SetOptionIfNotSet("CPACK_COMMAND_PRODUCTBUILD", program.c_str());
+  this->SetOptionIfNotSet("CPACK_COMMAND_PRODUCTBUILD", program);
 
   return this->Superclass::InitializeInternal();
 }
@@ -173,8 +174,8 @@ bool cmCPackProductBuildGenerator::GenerateComponentPackage(
 
   const char* comp_name = component ? component->Name.c_str() : nullptr;
 
-  const char* preflight = this->GetComponentScript("PREFLIGHT", comp_name);
-  const char* postflight = this->GetComponentScript("POSTFLIGHT", comp_name);
+  cmValue preflight = this->GetComponentScript("PREFLIGHT", comp_name);
+  cmValue postflight = this->GetComponentScript("POSTFLIGHT", comp_name);
 
   std::string resDir = packageFileDir;
   if (component) {
@@ -213,11 +214,11 @@ bool cmCPackProductBuildGenerator::GenerateComponentPackage(
   std::string version = this->GetOption("CPACK_PACKAGE_VERSION");
   std::string pkgbuild = this->GetOption("CPACK_COMMAND_PKGBUILD");
   std::string identityName;
-  if (const char* n = this->GetOption("CPACK_PKGBUILD_IDENTITY_NAME")) {
+  if (cmValue n = this->GetOption("CPACK_PKGBUILD_IDENTITY_NAME")) {
     identityName = n;
   }
   std::string keychainPath;
-  if (const char* p = this->GetOption("CPACK_PKGBUILD_KEYCHAIN_PATH")) {
+  if (cmValue p = this->GetOption("CPACK_PKGBUILD_KEYCHAIN_PATH")) {
     keychainPath = p;
   }
 
@@ -239,7 +240,7 @@ bool cmCPackProductBuildGenerator::GenerateComponentPackage(
   return RunProductBuild(pkgCmd.str());
 }
 
-const char* cmCPackProductBuildGenerator::GetComponentScript(
+cmValue cmCPackProductBuildGenerator::GetComponentScript(
   const char* script, const char* component_name)
 {
   std::string scriptname = std::string("CPACK_") + script + "_";
index 462e2fc..31cfafa 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "cmCPackGenerator.h"
 #include "cmCPackPKGGenerator.h"
+#include "cmValue.h"
 
 class cmCPackComponent;
 
@@ -45,6 +46,5 @@ protected:
                                 const std::string& packageDir,
                                 const cmCPackComponent* component);
 
-  const char* GetComponentScript(const char* script,
-                                 const char* script_component);
+  cmValue GetComponentScript(const char* script, const char* script_component);
 };
index c3f6d59..9e50700 100644 (file)
@@ -14,6 +14,7 @@
 #include "cmCPackLog.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmCPackRPMGenerator::cmCPackRPMGenerator() = default;
 
@@ -32,13 +33,13 @@ int cmCPackRPMGenerator::InitializeInternal()
   if (this->GetOption("CPACK_PACKAGE_NAME")) {
     std::string packageName = this->GetOption("CPACK_PACKAGE_NAME");
     std::replace(packageName.begin(), packageName.end(), ' ', '-');
-    this->SetOption("CPACK_PACKAGE_NAME", packageName.c_str());
+    this->SetOption("CPACK_PACKAGE_NAME", packageName);
   }
   /* same for CPACK_PACKAGE_FILE_NAME */
   if (this->GetOption("CPACK_PACKAGE_FILE_NAME")) {
     std::string packageName = this->GetOption("CPACK_PACKAGE_FILE_NAME");
     std::replace(packageName.begin(), packageName.end(), ' ', '-');
-    this->SetOption("CPACK_PACKAGE_FILE_NAME", packageName.c_str());
+    this->SetOption("CPACK_PACKAGE_FILE_NAME", packageName);
   }
   return this->Superclass::InitializeInternal();
 }
@@ -73,19 +74,17 @@ int cmCPackRPMGenerator::PackageOnePack(std::string const& initialToplevel,
 
   localToplevel += "/" + packageName;
   /* replace the TEMP DIRECTORY with the component one */
-  this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
+  this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel);
   packageFileName += "/" + outputFileName;
   /* replace proposed CPACK_OUTPUT_FILE_NAME */
-  this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
+  this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName);
   /* replace the TEMPORARY package file name */
-  this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
-                  packageFileName.c_str());
+  this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME", packageFileName);
   // Tell CPackRPM.cmake the name of the component NAME.
-  this->SetOption("CPACK_RPM_PACKAGE_COMPONENT", packageName.c_str());
+  this->SetOption("CPACK_RPM_PACKAGE_COMPONENT", packageName);
   // Tell CPackRPM.cmake the path where the component is.
   std::string component_path = cmStrCat('/', packageName);
-  this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_PATH",
-                  component_path.c_str());
+  this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_PATH", component_path);
   if (!this->ReadListFile("Internal/CPack/CPackRPM.cmake")) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Error while execution CPackRPM.cmake" << std::endl);
@@ -103,7 +102,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
   this->packageFileNames.clear();
   std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
 
-  const char* mainComponent = this->GetOption("CPACK_RPM_MAIN_COMPONENT");
+  cmValue mainComponent = this->GetOption("CPACK_RPM_MAIN_COMPONENT");
 
   if (this->IsOn("CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE") &&
       !this->IsOn("CPACK_RPM_DEBUGINFO_PACKAGE")) {
@@ -364,19 +363,17 @@ int cmCPackRPMGenerator::PackageComponentsAllInOne(
   localToplevel += "/" + compInstDirName;
 
   /* replace the TEMP DIRECTORY with the component one */
-  this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
+  this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel);
   packageFileName += "/" + outputFileName;
   /* replace proposed CPACK_OUTPUT_FILE_NAME */
-  this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
+  this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName);
   /* replace the TEMPORARY package file name */
-  this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
-                  packageFileName.c_str());
+  this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME", packageFileName);
 
   if (!compInstDirName.empty()) {
     // Tell CPackRPM.cmake the path where the component is.
     std::string component_path = cmStrCat('/', compInstDirName);
-    this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_PATH",
-                    component_path.c_str());
+    this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_PATH", component_path);
   }
 
   if (this->ReadListFile("Internal/CPack/CPackRPM.cmake")) {
index ad0a3e2..1340fb5 100644 (file)
@@ -15,6 +15,7 @@
 #include "cmCPackGenerator.h"
 #include "cmCPackLog.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmCPackSTGZGenerator::cmCPackSTGZGenerator()
   : cmCPackArchiveGenerator(cmArchiveWrite::CompressGZip, "paxr", ".sh")
@@ -33,7 +34,7 @@ int cmCPackSTGZGenerator::InitializeInternal()
                   "Cannot find template file: " << inFile << std::endl);
     return 0;
   }
-  this->SetOptionIfNotSet("CPACK_STGZ_HEADER_FILE", inFile.c_str());
+  this->SetOptionIfNotSet("CPACK_STGZ_HEADER_FILE", inFile);
   this->SetOptionIfNotSet("CPACK_AT_SIGN", "@");
 
   return this->Superclass::InitializeInternal();
@@ -78,8 +79,7 @@ int cmCPackSTGZGenerator::GenerateHeader(std::ostream* os)
   while (cmSystemTools::GetLineFromStream(ilfs, line)) {
     licenseText += line + "\n";
   }
-  this->SetOptionIfNotSet("CPACK_RESOURCE_FILE_LICENSE_CONTENT",
-                          licenseText.c_str());
+  this->SetOptionIfNotSet("CPACK_RESOURCE_FILE_LICENSE_CONTENT", licenseText);
 
   const char headerLengthTag[] = "###CPACK_HEADER_LENGTH###";
 
index a778939..54fd358 100644 (file)
 #include "cmDocumentationFormatter.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 namespace {
@@ -326,11 +326,11 @@ int main(int argc, char const* const* argv)
       cmSystemTools::CollapseFullPath(cpackProjectDirectory);
     globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY", cpackProjectDirectory);
 
-    cmProp cpackModulesPath = globalMF.GetDefinition("CPACK_MODULE_PATH");
+    cmValue cpackModulesPath = globalMF.GetDefinition("CPACK_MODULE_PATH");
     if (cpackModulesPath) {
       globalMF.AddDefinition("CMAKE_MODULE_PATH", *cpackModulesPath);
     }
-    cmProp genList = globalMF.GetDefinition("CPACK_GENERATOR");
+    cmValue genList = globalMF.GetDefinition("CPACK_GENERATOR");
     if (!genList) {
       cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
                   "CPack generator not specified" << std::endl);
@@ -408,20 +408,20 @@ int main(int argc, char const* const* argv)
             parsed = 0;
           }
           if (parsed) {
-            cmProp projName = mf->GetDefinition("CPACK_PACKAGE_NAME");
+            cmValue projName = mf->GetDefinition("CPACK_PACKAGE_NAME");
             cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
                         "Use generator: " << cpackGenerator->GetNameOfClass()
                                           << std::endl);
             cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
                         "For project: " << *projName << std::endl);
 
-            cmProp projVersion = mf->GetDefinition("CPACK_PACKAGE_VERSION");
+            cmValue projVersion = mf->GetDefinition("CPACK_PACKAGE_VERSION");
             if (!projVersion) {
-              cmProp projVersionMajor =
+              cmValue projVersionMajor =
                 mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR");
-              cmProp projVersionMinor =
+              cmValue projVersionMinor =
                 mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR");
-              cmProp projVersionPatch =
+              cmValue projVersionPatch =
                 mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH");
               std::ostringstream ostr;
               ostr << *projVersionMajor << "." << *projVersionMinor << "."
index 483c316..6e7c9e1 100644 (file)
@@ -11,9 +11,9 @@
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 class cmExecutionStatus;
@@ -39,13 +39,13 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
 
   this->Handler = handler;
 
-  cmProp ctestBuildCommand =
+  cmValue ctestBuildCommand =
     this->Makefile->GetDefinition("CTEST_BUILD_COMMAND");
   if (cmNonempty(ctestBuildCommand)) {
     this->CTest->SetCTestConfiguration("MakeCommand", *ctestBuildCommand,
                                        this->Quiet);
   } else {
-    cmProp cmakeGeneratorName =
+    cmValue cmakeGeneratorName =
       this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR");
 
     // Build configuration is determined by: CONFIGURATION argument,
@@ -53,7 +53,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
     // CTEST_CONFIGURATION_TYPE script variable, or ctest -C command
     // line argument... in that order.
     //
-    cmProp ctestBuildConfiguration =
+    cmValue ctestBuildConfiguration =
       this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION");
     std::string cmakeBuildConfiguration = cmNonempty(this->Configuration)
       ? this->Configuration
@@ -119,13 +119,13 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
     }
   }
 
-  if (cmProp useLaunchers =
+  if (cmValue useLaunchers =
         this->Makefile->GetDefinition("CTEST_USE_LAUNCHERS")) {
     this->CTest->SetCTestConfiguration("UseLaunchers", *useLaunchers,
                                        this->Quiet);
   }
 
-  if (cmProp labelsForSubprojects =
+  if (cmValue labelsForSubprojects =
         this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
     this->CTest->SetCTestConfiguration("LabelsForSubprojects",
                                        *labelsForSubprojects, this->Quiet);
index 03caa63..f9c4a8e 100644 (file)
 #include "cmGeneratedFileStream.h"
 #include "cmMakefile.h"
 #include "cmProcessOutput.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
 #include "cmStringReplaceHelper.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmXMLWriter.h"
 
 static const char* cmCTestErrorMatches[] = {
@@ -249,11 +249,11 @@ void cmCTestBuildHandler::PopulateCustomVectors(cmMakefile* mf)
   }
 
   // Record the user-specified custom warning rules.
-  if (cmProp customWarningMatchers =
+  if (cmValue customWarningMatchers =
         mf->GetDefinition("CTEST_CUSTOM_WARNING_MATCH")) {
     cmExpandList(*customWarningMatchers, this->ReallyCustomWarningMatches);
   }
-  if (cmProp customWarningExceptions =
+  if (cmValue customWarningExceptions =
         mf->GetDefinition("CTEST_CUSTOM_WARNING_EXCEPTION")) {
     cmExpandList(*customWarningExceptions,
                  this->ReallyCustomWarningExceptions);
index db9923e..fd20398 100644 (file)
@@ -12,9 +12,9 @@
 #include "cmCTestConfigureHandler.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 void cmCTestConfigureCommand::BindArguments()
@@ -39,14 +39,14 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
     return nullptr;
   }
 
-  cmProp ctestConfigureCommand =
+  cmValue ctestConfigureCommand =
     this->Makefile->GetDefinition("CTEST_CONFIGURE_COMMAND");
 
   if (cmNonempty(ctestConfigureCommand)) {
     this->CTest->SetCTestConfiguration("ConfigureCommand",
                                        *ctestConfigureCommand, this->Quiet);
   } else {
-    cmProp cmakeGeneratorName =
+    cmValue cmakeGeneratorName =
       this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR");
     if (cmNonempty(cmakeGeneratorName)) {
       const std::string& source_dir =
@@ -106,7 +106,7 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
       cmakeConfigureCommand += *cmakeGeneratorName;
       cmakeConfigureCommand += "\"";
 
-      cmProp cmakeGeneratorPlatform =
+      cmValue cmakeGeneratorPlatform =
         this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR_PLATFORM");
       if (cmNonempty(cmakeGeneratorPlatform)) {
         cmakeConfigureCommand += " \"-A";
@@ -114,7 +114,7 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
         cmakeConfigureCommand += "\"";
       }
 
-      cmProp cmakeGeneratorToolset =
+      cmValue cmakeGeneratorToolset =
         this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR_TOOLSET");
       if (cmNonempty(cmakeGeneratorToolset)) {
         cmakeConfigureCommand += " \"-T";
@@ -137,7 +137,7 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
     }
   }
 
-  if (cmProp labelsForSubprojects =
+  if (cmValue labelsForSubprojects =
         this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
     this->CTest->SetCTestConfiguration("LabelsForSubprojects",
                                        *labelsForSubprojects, this->Quiet);
index 568b091..d85edcc 100644 (file)
@@ -18,6 +18,7 @@
 #include "cmProcessTools.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 static unsigned int cmCTestGITVersion(unsigned int epic, unsigned int major,
                                       unsigned int minor, unsigned int fix)
index 48cc0e4..9800192 100644 (file)
@@ -21,11 +21,12 @@ cmCTestGenericHandler::cmCTestGenericHandler()
 
 cmCTestGenericHandler::~cmCTestGenericHandler() = default;
 
+namespace {
 /* Modify the given `map`, setting key `op` to `value` if `value`
  * is non-null, otherwise removing key `op` (if it exists).
  */
-static void SetMapValue(cmCTestGenericHandler::t_StringToString& map,
-                        const std::string& op, const char* value)
+void SetMapValue(cmCTestGenericHandler::t_StringToString& map,
+                 const std::string& op, const char* value)
 {
   if (!value) {
     map.erase(op);
@@ -34,11 +35,26 @@ static void SetMapValue(cmCTestGenericHandler::t_StringToString& map,
 
   map[op] = value;
 }
+void SetMapValue(cmCTestGenericHandler::t_StringToString& map,
+                 const std::string& op, cmValue value)
+{
+  if (!value) {
+    map.erase(op);
+    return;
+  }
+
+  map[op] = *value;
+}
+}
 
 void cmCTestGenericHandler::SetOption(const std::string& op, const char* value)
 {
   SetMapValue(this->Options, op, value);
 }
+void cmCTestGenericHandler::SetOption(const std::string& op, cmValue value)
+{
+  SetMapValue(this->Options, op, value);
+}
 
 void cmCTestGenericHandler::SetPersistentOption(const std::string& op,
                                                 const char* value)
@@ -46,6 +62,12 @@ void cmCTestGenericHandler::SetPersistentOption(const std::string& op,
   this->SetOption(op, value);
   SetMapValue(this->PersistentOptions, op, value);
 }
+void cmCTestGenericHandler::SetPersistentOption(const std::string& op,
+                                                cmValue value)
+{
+  this->SetOption(op, value);
+  SetMapValue(this->PersistentOptions, op, value);
+}
 
 void cmCTestGenericHandler::AddMultiOption(const std::string& op,
                                            const std::string& value)
@@ -72,13 +94,13 @@ void cmCTestGenericHandler::Initialize()
   this->MultiOptions = this->PersistentMultiOptions;
 }
 
-const char* cmCTestGenericHandler::GetOption(const std::string& op)
+cmValue cmCTestGenericHandler::GetOption(const std::string& op)
 {
   auto remit = this->Options.find(op);
   if (remit == this->Options.end()) {
     return nullptr;
   }
-  return remit->second.c_str();
+  return cmValue(remit->second);
 }
 
 std::vector<std::string> cmCTestGenericHandler::GetMultiOption(
index e846fd9..b4b0ad8 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "cmCTest.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 class cmGeneratedFileStream;
 class cmMakefile;
@@ -86,8 +87,18 @@ public:
    * as a multi-value will return nullptr.
    */
   void SetPersistentOption(const std::string& op, const char* value);
+  void SetPersistentOption(const std::string& op, const std::string& value)
+  {
+    this->SetPersistentOption(op, cmValue(value));
+  }
+  void SetPersistentOption(const std::string& op, cmValue value);
   void SetOption(const std::string& op, const char* value);
-  const char* GetOption(const std::string& op);
+  void SetOption(const std::string& op, const std::string& value)
+  {
+    this->SetOption(op, cmValue(value));
+  }
+  void SetOption(const std::string& op, cmValue value);
+  cmValue GetOption(const std::string& op);
 
   /**
    * Multi-Options collect one or more values from flags; passing
index 731932e..ea8feaa 100644 (file)
@@ -14,9 +14,9 @@
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmWorkingDirectory.h"
 
 namespace {
@@ -126,7 +126,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
   // CTEST_CONFIGURATION_TYPE script variable if it is defined.
   // The current script value trumps the -C argument on the command
   // line.
-  cmProp ctestConfigType =
+  cmValue ctestConfigType =
     this->Makefile->GetDefinition("CTEST_CONFIGURATION_TYPE");
   if (ctestConfigType) {
     this->CTest->SetConfigType(*ctestConfigType);
@@ -161,7 +161,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
       this->Quiet);
   }
 
-  if (cmProp changeId = this->Makefile->GetDefinition("CTEST_CHANGE_ID")) {
+  if (cmValue changeId = this->Makefile->GetDefinition("CTEST_CHANGE_ID")) {
     this->CTest->SetCTestConfiguration("ChangeId", *changeId, this->Quiet);
   }
 
index 125d003..6bb8e79 100644 (file)
@@ -305,7 +305,7 @@ int cmCTestMemCheckHandler::GetDefectCount() const
   return this->DefectCount;
 }
 
-void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml)
+void cmCTestMemCheckHandler::GenerateCTestXML(cmXMLWriter& xml)
 {
   if (!this->CTest->GetProduceXML()) {
     return;
index b200c43..a63a24d 100644 (file)
@@ -119,9 +119,9 @@ private:
   bool InitializeMemoryChecking();
 
   /**
-   * Generate the Dart compatible output
+   * Generate CTest DynamicAnalysis.xml files
    */
-  void GenerateDartOutput(cmXMLWriter& xml) override;
+  void GenerateCTestXML(cmXMLWriter& xml) override;
 
   std::vector<std::string> CustomPreMemCheck;
   std::vector<std::string> CustomPostMemCheck;
index 86a8e00..d90c4a6 100644 (file)
@@ -1026,6 +1026,11 @@ static Json::Value DumpCTestProperties(
     properties.append(DumpCTestProperty(
       "ENVIRONMENT", DumpToJsonArray(testProperties.Environment)));
   }
+  if (!testProperties.EnvironmentModification.empty()) {
+    properties.append(DumpCTestProperty(
+      "ENVIRONMENT_MODIFICATION",
+      DumpToJsonArray(testProperties.EnvironmentModification)));
+  }
   if (!testProperties.ErrorRegularExpressions.empty()) {
     properties.append(DumpCTestProperty(
       "FAIL_REGULAR_EXPRESSION",
index a892113..9d2cef6 100644 (file)
@@ -2,17 +2,22 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCTestRunTest.h"
 
+#include <algorithm>
 #include <chrono>
 #include <cstddef> // IWYU pragma: keep
 #include <cstdint>
 #include <cstdio>
 #include <cstring>
+#include <functional>
 #include <iomanip>
 #include <ratio>
 #include <sstream>
 #include <utility>
 
 #include <cm/memory>
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/string_view>
 
 #include "cmsys/RegularExpression.hxx"
 
@@ -44,7 +49,9 @@ void cmCTestRunTest::CheckOutput(std::string const& line)
   // Check for special CTest XML tags in this line of output.
   // If any are found, this line is excluded from ProcessOutput.
   if (!line.empty() && line.find("<CTest") != std::string::npos) {
+    bool ctest_tag_found = false;
     if (this->TestHandler->CustomCompletionStatusRegex.find(line)) {
+      ctest_tag_found = true;
       this->TestResult.CustomCompletionStatus =
         this->TestHandler->CustomCompletionStatusRegex.match(1);
       cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
@@ -52,6 +59,20 @@ void cmCTestRunTest::CheckOutput(std::string const& line)
                                   << "Test Details changed to '"
                                   << this->TestResult.CustomCompletionStatus
                                   << "'" << std::endl);
+    } else if (this->TestHandler->CustomLabelRegex.find(line)) {
+      ctest_tag_found = true;
+      auto label = this->TestHandler->CustomLabelRegex.match(1);
+      auto& labels = this->TestProperties->Labels;
+      if (std::find(labels.begin(), labels.end(), label) == labels.end()) {
+        labels.push_back(label);
+        std::sort(labels.begin(), labels.end());
+        cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+                   this->GetIndex()
+                     << ": "
+                     << "Test Label added: '" << label << "'" << std::endl);
+      }
+    }
+    if (ctest_tag_found) {
       return;
     }
   }
@@ -245,7 +266,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
     *this->TestHandler->LogFile << "Test time = " << buf << std::endl;
   }
 
-  this->DartProcessing();
+  this->ParseOutputForMeasurements();
 
   // if this is doing MemCheck then all the output needs to be put into
   // Output since that is what is parsed by cmCTestMemCheckHandler
@@ -623,6 +644,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
 
   return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout,
                            &this->TestProperties->Environment,
+                           &this->TestProperties->EnvironmentModification,
                            &this->TestProperties->Affinity);
 }
 
@@ -679,28 +701,45 @@ void cmCTestRunTest::ComputeArguments()
     cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                this->Index << ":  " << env << std::endl);
   }
+  if (!this->TestProperties->EnvironmentModification.empty()) {
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+               this->Index << ": "
+                           << "Environment variable modifications: "
+                           << std::endl);
+  }
+  for (std::string const& envmod :
+       this->TestProperties->EnvironmentModification) {
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+               this->Index << ":  " << envmod << std::endl);
+  }
 }
 
-void cmCTestRunTest::DartProcessing()
+void cmCTestRunTest::ParseOutputForMeasurements()
 {
   if (!this->ProcessOutput.empty() &&
-      this->ProcessOutput.find("<DartMeasurement") != std::string::npos) {
-    if (this->TestHandler->DartStuff.find(this->ProcessOutput)) {
-      this->TestResult.DartString = this->TestHandler->DartStuff.match(1);
+      (this->ProcessOutput.find("<DartMeasurement") != std::string::npos ||
+       this->ProcessOutput.find("<CTestMeasurement") != std::string::npos)) {
+    if (this->TestHandler->AllTestMeasurementsRegex.find(
+          this->ProcessOutput)) {
+      this->TestResult.TestMeasurementsOutput =
+        this->TestHandler->AllTestMeasurementsRegex.match(1);
       // keep searching and replacing until none are left
-      while (this->TestHandler->DartStuff1.find(this->ProcessOutput)) {
+      while (this->TestHandler->SingleTestMeasurementRegex.find(
+        this->ProcessOutput)) {
         // replace the exact match for the string
         cmSystemTools::ReplaceString(
-          this->ProcessOutput, this->TestHandler->DartStuff1.match(1).c_str(),
-          "");
+          this->ProcessOutput,
+          this->TestHandler->SingleTestMeasurementRegex.match(1).c_str(), "");
       }
     }
   }
 }
 
-bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
-                                 std::vector<std::string>* environment,
-                                 std::vector<size_t>* affinity)
+bool cmCTestRunTest::ForkProcess(
+  cmDuration testTimeOut, bool explicitTimeout,
+  std::vector<std::string>* environment,
+  std::vector<std::string>* environment_modification,
+  std::vector<size_t>* affinity)
 {
   this->TestProcess->SetId(this->Index);
   this->TestProcess->SetWorkingDirectory(this->TestProperties->Directory);
@@ -743,12 +782,145 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
 
   std::ostringstream envMeasurement;
   if (environment && !environment->empty()) {
+    // Environment modification works on the assumption that the environment is
+    // actually modified here. If another strategy is used, there will need to
+    // be updates below in `apply_diff`.
     cmSystemTools::AppendEnv(*environment);
     for (auto const& var : *environment) {
       envMeasurement << var << std::endl;
     }
   }
 
+  if (environment_modification && !environment_modification->empty()) {
+    std::map<std::string, cm::optional<std::string>> env_application;
+
+#ifdef _WIN32
+    char path_sep = ';';
+#else
+    char path_sep = ':';
+#endif
+
+    auto apply_diff =
+      [&env_application](const std::string& name,
+                         std::function<void(std::string&)> const& apply) {
+        cm::optional<std::string> old_value = env_application[name];
+        std::string output;
+        if (old_value) {
+          output = *old_value;
+        } else {
+          // This only works because the environment is actually modified above
+          // (`AppendEnv`). If CTest ever just creates an environment block
+          // directly, that block will need to be queried for the subprocess'
+          // value instead.
+          const char* curval = cmSystemTools::GetEnv(name);
+          if (curval) {
+            output = curval;
+          }
+        }
+        apply(output);
+        env_application[name] = output;
+      };
+
+    bool err_occurred = false;
+
+    for (auto const& envmod : *environment_modification) {
+      // Split on `=`
+      auto const eq_loc = envmod.find_first_of('=');
+      if (eq_loc == std::string::npos) {
+        cmCTestLog(this->CTest, ERROR_MESSAGE,
+                   "Error: Missing `=` after the variable name in: "
+                     << envmod << std::endl);
+        err_occurred = true;
+        continue;
+      }
+      auto const name = envmod.substr(0, eq_loc);
+
+      // Split value on `:`
+      auto const op_value_start = eq_loc + 1;
+      auto const colon_loc = envmod.find_first_of(':', op_value_start);
+      if (colon_loc == std::string::npos) {
+        cmCTestLog(this->CTest, ERROR_MESSAGE,
+                   "Error: Missing `:` after the operation in: " << envmod
+                                                                 << std::endl);
+        err_occurred = true;
+        continue;
+      }
+      auto const op =
+        envmod.substr(op_value_start, colon_loc - op_value_start);
+
+      auto const value_start = colon_loc + 1;
+      auto const value = envmod.substr(value_start);
+
+      // Determine what to do with the operation.
+      if (op == "reset"_s) {
+        auto entry = env_application.find(name);
+        if (entry != env_application.end()) {
+          env_application.erase(entry);
+        }
+      } else if (op == "set"_s) {
+        env_application[name] = value;
+      } else if (op == "unset"_s) {
+        env_application[name] = {};
+      } else if (op == "string_append"_s) {
+        apply_diff(name, [&value](std::string& output) { output += value; });
+      } else if (op == "string_prepend"_s) {
+        apply_diff(name,
+                   [&value](std::string& output) { output.insert(0, value); });
+      } else if (op == "path_list_append"_s) {
+        apply_diff(name, [&value, path_sep](std::string& output) {
+          if (!output.empty()) {
+            output += path_sep;
+          }
+          output += value;
+        });
+      } else if (op == "path_list_prepend"_s) {
+        apply_diff(name, [&value, path_sep](std::string& output) {
+          if (!output.empty()) {
+            output.insert(output.begin(), path_sep);
+          }
+          output.insert(0, value);
+        });
+      } else if (op == "cmake_list_append"_s) {
+        apply_diff(name, [&value](std::string& output) {
+          if (!output.empty()) {
+            output += ';';
+          }
+          output += value;
+        });
+      } else if (op == "cmake_list_prepend"_s) {
+        apply_diff(name, [&value](std::string& output) {
+          if (!output.empty()) {
+            output.insert(output.begin(), ';');
+          }
+          output.insert(0, value);
+        });
+      } else {
+        cmCTestLog(this->CTest, ERROR_MESSAGE,
+                   "Error: Unrecognized environment manipulation argument: "
+                     << op << std::endl);
+        err_occurred = true;
+        continue;
+      }
+    }
+
+    if (err_occurred) {
+      return false;
+    }
+
+    for (auto const& env_apply : env_application) {
+      if (env_apply.second) {
+        auto const env_update =
+          cmStrCat(env_apply.first, '=', *env_apply.second);
+        cmSystemTools::PutEnv(env_update);
+        envMeasurement << env_update << std::endl;
+      } else {
+        cmSystemTools::UnsetEnv(env_apply.first.c_str());
+        // Signify that this variable is being actively unset
+        envMeasurement << "#" << env_apply.first << "=" << std::endl;
+      }
+    }
+  }
+
   if (this->UseAllocatedResources) {
     std::vector<std::string> envLog;
     this->SetupResourcesEnvironment(&envLog);
index 863ac1b..2082156 100644 (file)
@@ -109,10 +109,11 @@ public:
 
 private:
   bool NeedsToRepeat();
-  void DartProcessing();
+  void ParseOutputForMeasurements();
   void ExeNotFound(std::string exe);
   bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
                    std::vector<std::string>* environment,
+                   std::vector<std::string>* environment_modification,
                    std::vector<size_t>* affinity);
   void WriteLogOutputTop(size_t completed, size_t total);
   // Run post processing of the process output for MemCheck
index d2cad39..f685f66 100644 (file)
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 #ifdef _WIN32
@@ -372,8 +372,8 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
 int cmCTestScriptHandler::ExtractVariables()
 {
   // Temporary variables
-  cmProp minInterval;
-  cmProp contDuration;
+  cmValue minInterval;
+  cmValue contDuration;
 
   this->SourceDir =
     this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
@@ -412,7 +412,7 @@ int cmCTestScriptHandler::ExtractVariables()
   int i;
   for (i = 1; i < 10; ++i) {
     sprintf(updateVar, "CTEST_EXTRA_UPDATES_%i", i);
-    cmProp updateVal = this->Makefile->GetDefinition(updateVar);
+    cmValue updateVal = this->Makefile->GetDefinition(updateVar);
     if (updateVal) {
       if (this->UpdateCmd.empty()) {
         cmSystemTools::Error(
@@ -930,7 +930,7 @@ cmDuration cmCTestScriptHandler::GetRemainingTimeAllowed()
     return cmCTest::MaxDuration();
   }
 
-  cmProp timelimitS = this->Makefile->GetDefinition("CTEST_TIME_LIMIT");
+  cmValue timelimitS = this->Makefile->GetDefinition("CTEST_TIME_LIMIT");
 
   if (!timelimitS) {
     return cmCTest::MaxDuration();
index 53e1b2f..84d12d7 100644 (file)
@@ -9,8 +9,8 @@
 #include "cmCTestVC.h"
 #include "cmGeneratedFileStream.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 class cmExecutionStatus;
 
@@ -30,8 +30,8 @@ bool cmCTestStartCommand::InitialPass(std::vector<std::string> const& args,
 
   size_t cnt = 0;
   const char* smodel = nullptr;
-  const std::string* src_dir = nullptr;
-  const std::string* bld_dir = nullptr;
+  cmValue src_dir;
+  cmValue bld_dir;
 
   while (cnt < args.size()) {
     if (args[cnt] == "GROUP" || args[cnt] == "TRACK") {
@@ -55,10 +55,10 @@ bool cmCTestStartCommand::InitialPass(std::vector<std::string> const& args,
       smodel = args[cnt].c_str();
       cnt++;
     } else if (!src_dir) {
-      src_dir = &args[cnt];
+      src_dir = cmValue(args[cnt]);
       cnt++;
     } else if (!bld_dir) {
-      bld_dir = &args[cnt];
+      bld_dir = cmValue(args[cnt]);
       cnt++;
     } else {
       this->SetError("Too many arguments");
@@ -162,7 +162,7 @@ bool cmCTestStartCommand::InitialCheckout(std::ostream& ofs,
                                           std::string const& sourceDir)
 {
   // Use the user-provided command to create the source tree.
-  cmProp initialCheckoutCommand =
+  cmValue initialCheckoutCommand =
     this->Makefile->GetDefinition("CTEST_CHECKOUT_COMMAND");
   if (!initialCheckoutCommand) {
     initialCheckoutCommand =
index bdba0e5..c4f87e9 100644 (file)
 #include "cmCommand.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 class cmExecutionStatus;
 
@@ -36,8 +36,8 @@ std::unique_ptr<cmCommand> cmCTestSubmitCommand::Clone()
 
 cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
 {
-  const std::string* submitURL = !this->SubmitURL.empty()
-    ? &this->SubmitURL
+  cmValue submitURL = !this->SubmitURL.empty()
+    ? cmValue(this->SubmitURL)
     : this->Makefile->GetDefinition("CTEST_SUBMIT_URL");
 
   if (submitURL) {
@@ -59,14 +59,14 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
   this->CTest->SetCTestConfigurationFromCMakeVariable(
     this->Makefile, "CurlOptions", "CTEST_CURL_OPTIONS", this->Quiet);
 
-  cmProp notesFilesVariable =
+  cmValue notesFilesVariable =
     this->Makefile->GetDefinition("CTEST_NOTES_FILES");
   if (notesFilesVariable) {
     std::vector<std::string> notesFiles = cmExpandedList(*notesFilesVariable);
     this->CTest->GenerateNotesFile(notesFiles);
   }
 
-  cmProp extraFilesVariable =
+  cmValue extraFilesVariable =
     this->Makefile->GetDefinition("CTEST_EXTRA_SUBMIT_FILES");
   if (extraFilesVariable) {
     std::vector<std::string> extraFiles = cmExpandedList(*extraFilesVariable);
@@ -119,15 +119,15 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
     handler->SetHttpHeaders(this->HttpHeaders);
   }
 
-  handler->SetOption("RetryDelay", this->RetryDelay.c_str());
-  handler->SetOption("RetryCount", this->RetryCount.c_str());
+  handler->SetOption("RetryDelay", this->RetryDelay);
+  handler->SetOption("RetryCount", this->RetryCount);
   handler->SetOption("InternalTest", this->InternalTest ? "ON" : "OFF");
 
   handler->SetQuiet(this->Quiet);
 
   if (this->CDashUpload) {
-    handler->SetOption("CDashUploadFile", this->CDashUploadFile.c_str());
-    handler->SetOption("CDashUploadType", this->CDashUploadType.c_str());
+    handler->SetOption("CDashUploadFile", this->CDashUploadFile);
+    handler->SetOption("CDashUploadType", this->CDashUploadType);
   }
   return handler;
 }
index 5b54573..b99bb79 100644 (file)
 #include "cmCurl.h"
 #include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmXMLParser.h"
 #include "cmake.h"
 
@@ -261,7 +261,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
         cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
         cmake* cm = ch->GetCMake();
         if (cm) {
-          cmProp subproject = cm->GetState()->GetGlobalProperty("SubProject");
+          cmValue subproject = cm->GetState()->GetGlobalProperty("SubProject");
           if (subproject) {
             upload_as += "&subproject=";
             upload_as += ctest_curl.Escape(*subproject);
@@ -357,12 +357,8 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
       // If curl failed for any reason, or checksum fails, wait and retry
       //
       if (res != CURLE_OK || this->HasErrors) {
-        std::string retryDelay = this->GetOption("RetryDelay") == nullptr
-          ? ""
-          : this->GetOption("RetryDelay");
-        std::string retryCount = this->GetOption("RetryCount") == nullptr
-          ? ""
-          : this->GetOption("RetryCount");
+        std::string retryDelay = *this->GetOption("RetryDelay");
+        std::string retryCount = *this->GetOption("RetryCount");
 
         auto delay = cmDuration(
           retryDelay.empty()
@@ -522,12 +518,8 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
   bool internalTest = cmIsOn(this->GetOption("InternalTest"));
 
   // Get RETRY_COUNT and RETRY_DELAY values if they were set.
-  std::string retryDelayString = this->GetOption("RetryDelay") == nullptr
-    ? ""
-    : this->GetOption("RetryDelay");
-  std::string retryCountString = this->GetOption("RetryCount") == nullptr
-    ? ""
-    : this->GetOption("RetryCount");
+  std::string retryDelayString = *this->GetOption("RetryDelay");
+  std::string retryCountString = *this->GetOption("RetryCount");
   auto retryDelay = std::chrono::seconds(0);
   if (!retryDelayString.empty()) {
     unsigned long retryDelayValue = 0;
@@ -556,7 +548,7 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
   // a "&subproject=subprojectname" to the first POST.
   cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
   cmake* cm = ch->GetCMake();
-  cmProp subproject = cm->GetState()->GetGlobalProperty("SubProject");
+  cmValue subproject = cm->GetState()->GetGlobalProperty("SubProject");
   // TODO: Encode values for a URL instead of trusting caller.
   std::ostringstream str;
   if (subproject) {
@@ -716,8 +708,8 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
 
 int cmCTestSubmitHandler::ProcessHandler()
 {
-  const char* cdashUploadFile = this->GetOption("CDashUploadFile");
-  const char* cdashUploadType = this->GetOption("CDashUploadType");
+  cmValue cdashUploadFile = this->GetOption("CDashUploadFile");
+  cmValue cdashUploadType = this->GetOption("CDashUploadType");
   if (cdashUploadFile && cdashUploadType) {
     return this->HandleCDashUploadFile(cdashUploadFile, cdashUploadType);
   }
@@ -804,6 +796,7 @@ int cmCTestSubmitHandler::ProcessHandler()
     }
   }
   this->CTest->AddIfExists(cmCTest::PartMemCheck, "DynamicAnalysis.xml");
+  this->CTest->AddIfExists(cmCTest::PartMemCheck, "DynamicAnalysis-Test.xml");
   this->CTest->AddIfExists(cmCTest::PartMemCheck, "Purify.xml");
   this->CTest->AddIfExists(cmCTest::PartNotes, "Notes.xml");
   this->CTest->AddIfExists(cmCTest::PartUpload, "Upload.xml");
index 67f4986..5488388 100644 (file)
@@ -12,8 +12,8 @@
 #include "cmCTestTestHandler.h"
 #include "cmDuration.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
+#include "cmValue.h"
 
 void cmCTestTestCommand::BindArguments()
 {
@@ -40,7 +40,7 @@ void cmCTestTestCommand::BindArguments()
 
 cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
 {
-  cmProp ctestTimeout = this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT");
+  cmValue ctestTimeout = this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT");
 
   cmDuration timeout;
   if (ctestTimeout) {
@@ -54,7 +54,7 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
   }
   this->CTest->SetTimeOut(timeout);
 
-  cmProp resourceSpecFile =
+  cmValue resourceSpecFile =
     this->Makefile->GetDefinition("CTEST_RESOURCE_SPEC_FILE");
   if (this->ResourceSpecFile.empty() && resourceSpecFile) {
     this->ResourceSpecFile = *resourceSpecFile;
@@ -64,13 +64,13 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
   if (!this->Start.empty() || !this->End.empty() || !this->Stride.empty()) {
     handler->SetOption(
       "TestsToRunInformation",
-      cmStrCat(this->Start, ',', this->End, ',', this->Stride).c_str());
+      cmStrCat(this->Start, ',', this->End, ',', this->Stride));
   }
   if (!this->Exclude.empty()) {
-    handler->SetOption("ExcludeRegularExpression", this->Exclude.c_str());
+    handler->SetOption("ExcludeRegularExpression", this->Exclude);
   }
   if (!this->Include.empty()) {
-    handler->SetOption("IncludeRegularExpression", this->Include.c_str());
+    handler->SetOption("IncludeRegularExpression", this->Include);
   }
   if (!this->ExcludeLabel.empty()) {
     handler->AddMultiOption("ExcludeLabelRegularExpression",
@@ -81,30 +81,30 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
   }
   if (!this->ExcludeFixture.empty()) {
     handler->SetOption("ExcludeFixtureRegularExpression",
-                       this->ExcludeFixture.c_str());
+                       this->ExcludeFixture);
   }
   if (!this->ExcludeFixtureSetup.empty()) {
     handler->SetOption("ExcludeFixtureSetupRegularExpression",
-                       this->ExcludeFixtureSetup.c_str());
+                       this->ExcludeFixtureSetup);
   }
   if (!this->ExcludeFixtureCleanup.empty()) {
     handler->SetOption("ExcludeFixtureCleanupRegularExpression",
-                       this->ExcludeFixtureCleanup.c_str());
+                       this->ExcludeFixtureCleanup);
   }
   if (this->StopOnFailure) {
     handler->SetOption("StopOnFailure", "ON");
   }
   if (!this->ParallelLevel.empty()) {
-    handler->SetOption("ParallelLevel", this->ParallelLevel.c_str());
+    handler->SetOption("ParallelLevel", this->ParallelLevel);
   }
   if (!this->Repeat.empty()) {
-    handler->SetOption("Repeat", this->Repeat.c_str());
+    handler->SetOption("Repeat", this->Repeat);
   }
   if (!this->ScheduleRandom.empty()) {
-    handler->SetOption("ScheduleRandom", this->ScheduleRandom.c_str());
+    handler->SetOption("ScheduleRandom", this->ScheduleRandom);
   }
   if (!this->ResourceSpecFile.empty()) {
-    handler->SetOption("ResourceSpecFile", this->ResourceSpecFile.c_str());
+    handler->SetOption("ResourceSpecFile", this->ResourceSpecFile);
   }
   if (!this->StopTime.empty()) {
     this->CTest->SetStopTime(this->StopTime);
@@ -114,7 +114,7 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
   // or CTEST_TEST_LOAD script variable, or ctest --test-load
   // command line argument... in that order.
   unsigned long testLoad;
-  cmProp ctestTestLoad = this->Makefile->GetDefinition("CTEST_TEST_LOAD");
+  cmValue ctestTestLoad = this->Makefile->GetDefinition("CTEST_TEST_LOAD");
   if (!this->TestLoad.empty()) {
     if (!cmStrToULong(this->TestLoad, &testLoad)) {
       testLoad = 0;
@@ -134,7 +134,7 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
   }
   handler->SetTestLoad(testLoad);
 
-  if (cmProp labelsForSubprojects =
+  if (cmValue labelsForSubprojects =
         this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
     this->CTest->SetCTestConfiguration("LabelsForSubprojects",
                                        *labelsForSubprojects, this->Quiet);
index 730ec0f..6e97a83 100644 (file)
 #include "cmCTest.h"
 #include "cmCTestMultiProcessHandler.h"
 #include "cmCTestResourceGroupsLexerHelper.h"
+#include "cmCTestTestMeasurementXMLParser.h"
 #include "cmDuration.h"
 #include "cmExecutionStatus.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTimestamp.h"
+#include "cmValue.h"
 #include "cmWorkingDirectory.h"
 #include "cmXMLWriter.h"
 #include "cmake.h"
@@ -303,15 +304,24 @@ cmCTestTestHandler::cmCTestTestHandler()
   // Support for JUnit XML output.
   this->JUnitXMLFileName = "";
 
-  // regex to detect <DartMeasurement>...</DartMeasurement>
-  this->DartStuff.compile("(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)");
-  // regex to detect each individual <DartMeasurement>...</DartMeasurement>
-  this->DartStuff1.compile(
-    "(<DartMeasurement[^<]*</DartMeasurement[a-zA-Z]*>)");
+  // Regular expressions to scan test output for custom measurements.
 
-  // regex to detect <CTestDetails>...</CTestDetails>
+  // Capture the whole section of test output from the first opening
+  // <(CTest|Dart)Measurement*> tag to the last </(CTest|Dart)Measurement*>
+  // closing tag.
+  this->AllTestMeasurementsRegex.compile(
+    "(<(CTest|Dart)Measurement.*/(CTest|Dart)Measurement[a-zA-Z]*>)");
+
+  // Capture a single <(CTest|Dart)Measurement*> XML element.
+  this->SingleTestMeasurementRegex.compile(
+    "(<(CTest|Dart)Measurement[^<]*</(CTest|Dart)Measurement[a-zA-Z]*>)");
+
+  // Capture content from <CTestDetails>...</CTestDetails>
   this->CustomCompletionStatusRegex.compile(
     "<CTestDetails>(.*)</CTestDetails>");
+
+  // Capture content from <CTestLabel>...</CTestLabel>
+  this->CustomLabelRegex.compile("<CTestLabel>(.*)</CTestLabel>");
 }
 
 void cmCTestTestHandler::Initialize()
@@ -511,7 +521,7 @@ bool cmCTestTestHandler::ProcessOptions()
   if (cmIsOn(this->GetOption("ScheduleRandom"))) {
     this->CTest->SetScheduleType("Random");
   }
-  if (const char* repeat = this->GetOption("Repeat")) {
+  if (cmValue repeat = this->GetOption("Repeat")) {
     cmsys::RegularExpression repeatRegex(
       "^(UNTIL_FAIL|UNTIL_PASS|AFTER_TIMEOUT):([0-9]+)$");
     if (repeatRegex.find(repeat)) {
@@ -536,7 +546,7 @@ bool cmCTestTestHandler::ProcessOptions()
     }
   }
   if (this->GetOption("ParallelLevel")) {
-    this->CTest->SetParallelLevel(atoi(this->GetOption("ParallelLevel")));
+    this->CTest->SetParallelLevel(std::stoi(this->GetOption("ParallelLevel")));
   }
 
   if (this->GetOption("StopOnFailure")) {
@@ -547,7 +557,7 @@ bool cmCTestTestHandler::ProcessOptions()
                this->IncludeLabelRegularExpressions);
   BuildLabelRE(this->GetMultiOption("ExcludeLabelRegularExpression"),
                this->ExcludeLabelRegularExpressions);
-  const char* val = this->GetOption("IncludeRegularExpression");
+  cmValue val = this->GetOption("IncludeRegularExpression");
   if (val) {
     this->UseIncludeRegExp();
     this->SetIncludeRegExp(val);
@@ -559,19 +569,19 @@ bool cmCTestTestHandler::ProcessOptions()
   }
   val = this->GetOption("ExcludeFixtureRegularExpression");
   if (val) {
-    this->ExcludeFixtureRegExp = val;
+    this->ExcludeFixtureRegExp = *val;
   }
   val = this->GetOption("ExcludeFixtureSetupRegularExpression");
   if (val) {
-    this->ExcludeFixtureSetupRegExp = val;
+    this->ExcludeFixtureSetupRegExp = *val;
   }
   val = this->GetOption("ExcludeFixtureCleanupRegularExpression");
   if (val) {
-    this->ExcludeFixtureCleanupRegExp = val;
+    this->ExcludeFixtureCleanupRegExp = *val;
   }
   val = this->GetOption("ResourceSpecFile");
   if (val) {
-    this->ResourceSpecFile = val;
+    this->ResourceSpecFile = *val;
   }
   this->SetRerunFailed(cmIsOn(this->GetOption("RerunFailed")));
 
@@ -692,7 +702,22 @@ bool cmCTestTestHandler::GenerateXML()
       return false;
     }
     cmXMLWriter xml(xmlfile);
-    this->GenerateDartOutput(xml);
+    this->GenerateCTestXML(xml);
+  }
+
+  if (this->MemCheck) {
+    cmGeneratedFileStream xmlfile;
+    if (!this->StartResultingXML(cmCTest::PartTest, "DynamicAnalysis-Test",
+                                 xmlfile)) {
+      cmCTestLog(this->CTest, ERROR_MESSAGE,
+                 "Cannot create testing XML file" << std::endl);
+      this->LogFile = nullptr;
+      return false;
+    }
+    cmXMLWriter xml(xmlfile);
+    // Explicitly call this class' `GenerateCTestXML` method to make `Test.xml`
+    // as well.
+    this->cmCTestTestHandler::GenerateCTestXML(xml);
   }
 
   return true;
@@ -1400,7 +1425,7 @@ void cmCTestTestHandler::GenerateTestCommand(
 {
 }
 
-void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml)
+void cmCTestTestHandler::GenerateCTestXML(cmXMLWriter& xml)
 {
   if (!this->CTest->GetProduceXML()) {
     return;
@@ -1436,7 +1461,7 @@ void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml)
         xml.Element("Value", result.ReturnValue);
         xml.EndElement(); // NamedMeasurement
       }
-      this->GenerateRegressionImages(xml, result.DartString);
+      this->RecordCustomTestMeasurements(xml, result.TestMeasurementsOutput);
       xml.StartElement("NamedMeasurement");
       xml.Attribute("type", "numeric/double");
       xml.Attribute("name", "Execution Time");
@@ -1804,7 +1829,7 @@ bool cmCTestTestHandler::GetListOfTests()
     // SEND_ERROR or FATAL_ERROR in CTestTestfile or TEST_INCLUDE_FILES
     return false;
   }
-  cmProp specFile = mf.GetDefinition("CTEST_RESOURCE_SPEC_FILE");
+  cmValue specFile = mf.GetDefinition("CTEST_RESOURCE_SPEC_FILE");
   if (this->ResourceSpecFile.empty() && specFile) {
     this->ResourceSpecFile = *specFile;
   }
@@ -1976,124 +2001,48 @@ void cmCTestTestHandler::ExpandTestsToRunInformationForRerunFailed()
   }
 }
 
-// Just for convenience
-#define SPACE_REGEX "[ \t\r\n]"
-void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml,
-                                                  const std::string& dart)
-{
-  cmsys::RegularExpression twoattributes(
-    "<DartMeasurement" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*>([^<]*)</DartMeasurement>");
-  cmsys::RegularExpression threeattributes(
-    "<DartMeasurement" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*>([^<]*)</DartMeasurement>");
-  cmsys::RegularExpression fourattributes(
-    "<DartMeasurement" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*>([^<]*)</DartMeasurement>");
-  cmsys::RegularExpression cdatastart(
-    "<DartMeasurement" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*>" SPACE_REGEX "*<!\\[CDATA\\[");
-  cmsys::RegularExpression cdataend("]]>" SPACE_REGEX "*</DartMeasurement>");
-  cmsys::RegularExpression measurementfile(
-    "<DartMeasurementFile" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
-    "*>([^<]*)</DartMeasurementFile>");
-
-  bool done = false;
-  std::string cxml = dart;
-  while (!done) {
-    if (twoattributes.find(cxml)) {
-      xml.StartElement("NamedMeasurement");
-      xml.Attribute(twoattributes.match(1).c_str(), twoattributes.match(2));
-      xml.Attribute(twoattributes.match(3).c_str(), twoattributes.match(4));
-      xml.Element("Value", twoattributes.match(5));
-      xml.EndElement();
-      cxml.erase(twoattributes.start(),
-                 twoattributes.end() - twoattributes.start());
-    } else if (threeattributes.find(cxml)) {
-      xml.StartElement("NamedMeasurement");
-      xml.Attribute(threeattributes.match(1).c_str(),
-                    threeattributes.match(2));
-      xml.Attribute(threeattributes.match(3).c_str(),
-                    threeattributes.match(4));
-      xml.Attribute(threeattributes.match(5).c_str(),
-                    threeattributes.match(6));
-      xml.Element("Value", twoattributes.match(7));
-      xml.EndElement();
-      cxml.erase(threeattributes.start(),
-                 threeattributes.end() - threeattributes.start());
-    } else if (fourattributes.find(cxml)) {
+void cmCTestTestHandler::RecordCustomTestMeasurements(cmXMLWriter& xml,
+                                                      std::string content)
+{
+  while (this->SingleTestMeasurementRegex.find(content)) {
+    // Extract regex match from content and parse it as an XML element.
+    auto measurement_str = this->SingleTestMeasurementRegex.match(1);
+    auto parser = cmCTestTestMeasurementXMLParser();
+    parser.Parse(measurement_str.c_str());
+
+    if (parser.ElementName == "CTestMeasurement" ||
+        parser.ElementName == "DartMeasurement") {
       xml.StartElement("NamedMeasurement");
-      xml.Attribute(fourattributes.match(1).c_str(), fourattributes.match(2));
-      xml.Attribute(fourattributes.match(3).c_str(), fourattributes.match(4));
-      xml.Attribute(fourattributes.match(5).c_str(), fourattributes.match(6));
-      xml.Attribute(fourattributes.match(7).c_str(), fourattributes.match(8));
-      xml.Element("Value", twoattributes.match(9));
+      xml.Attribute("type", parser.MeasurementType);
+      xml.Attribute("name", parser.MeasurementName);
+      xml.Element("Value", parser.CharacterData);
       xml.EndElement();
-      cxml.erase(fourattributes.start(),
-                 fourattributes.end() - fourattributes.start());
-    } else if (cdatastart.find(cxml) && cdataend.find(cxml)) {
-      xml.StartElement("NamedMeasurement");
-      xml.Attribute(cdatastart.match(1).c_str(), cdatastart.match(2));
-      xml.Attribute(cdatastart.match(3).c_str(), cdatastart.match(4));
-      xml.StartElement("Value");
-      xml.CData(
-        cxml.substr(cdatastart.end(), cdataend.start() - cdatastart.end()));
-      xml.EndElement(); // Value
-      xml.EndElement(); // NamedMeasurement
-      cxml.erase(cdatastart.start(), cdataend.end() - cdatastart.start());
-    } else if (measurementfile.find(cxml)) {
-      const std::string& filename =
-        cmCTest::CleanString(measurementfile.match(5));
-      if (cmSystemTools::FileExists(filename)) {
+    } else if (parser.ElementName == "CTestMeasurementFile" ||
+               parser.ElementName == "DartMeasurementFile") {
+      const std::string& filename = cmCTest::CleanString(parser.CharacterData);
+      if (!cmSystemTools::FileExists(filename)) {
+        xml.StartElement("NamedMeasurement");
+        xml.Attribute("name", parser.MeasurementName);
+        xml.Attribute("text", "text/string");
+        xml.Element("Value", "File " + filename + " not found");
+        xml.EndElement();
+        cmCTestOptionalLog(
+          this->CTest, HANDLER_OUTPUT,
+          "File \"" << filename << "\" not found." << std::endl, this->Quiet);
+      } else {
         long len = cmSystemTools::FileLength(filename);
-        std::string k1 = measurementfile.match(1);
-        std::string v1 = measurementfile.match(2);
-        std::string k2 = measurementfile.match(3);
-        std::string v2 = measurementfile.match(4);
         if (len == 0) {
-          if (cmSystemTools::LowerCase(k1) == "type") {
-            v1 = "text/string";
-          }
-          if (cmSystemTools::LowerCase(k2) == "type") {
-            v2 = "text/string";
-          }
-
           xml.StartElement("NamedMeasurement");
-          xml.Attribute(k1.c_str(), v1);
-          xml.Attribute(k2.c_str(), v2);
+          xml.Attribute("name", parser.MeasurementName);
+          xml.Attribute("type", "text/string");
           xml.Attribute("encoding", "none");
           xml.Element("Value", "Image " + filename + " is empty");
           xml.EndElement();
         } else {
-          std::string type;
-          std::string name;
-          if (cmSystemTools::LowerCase(k1) == "type") {
-            type = v1;
-          } else if (cmSystemTools::LowerCase(k2) == "type") {
-            type = v2;
-          }
-          if (cmSystemTools::LowerCase(k1) == "name") {
-            name = v1;
-          } else if (cmSystemTools::LowerCase(k2) == "name") {
-            name = v2;
-          }
-          if (type == "file") {
+          if (parser.MeasurementType == "file") {
             // Treat this measurement like an "ATTACHED_FILE" when the type
             // is explicitly "file" (not an image).
-            this->AttachFile(xml, filename, name);
+            this->AttachFile(xml, filename, parser.MeasurementName);
           } else {
             cmsys::ifstream ifs(filename.c_str(),
                                 std::ios::in
@@ -2110,10 +2059,8 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml,
                                              encoded_buffer.get(), 1);
 
             xml.StartElement("NamedMeasurement");
-            xml.Attribute(measurementfile.match(1).c_str(),
-                          measurementfile.match(2));
-            xml.Attribute(measurementfile.match(3).c_str(),
-                          measurementfile.match(4));
+            xml.Attribute("name", parser.MeasurementName);
+            xml.Attribute("type", parser.MeasurementType);
             xml.Attribute("encoding", "base64");
             std::ostringstream ostr;
             for (size_t cc = 0; cc < rlen; cc++) {
@@ -2126,48 +2073,34 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml,
             xml.EndElement(); // NamedMeasurement
           }
         }
-      } else {
-        int idx = 4;
-        if (measurementfile.match(1) == "name") {
-          idx = 2;
-        }
-        xml.StartElement("NamedMeasurement");
-        xml.Attribute("name", measurementfile.match(idx));
-        xml.Attribute("text", "text/string");
-        xml.Element("Value", "File " + filename + " not found");
-        xml.EndElement();
-        cmCTestOptionalLog(
-          this->CTest, HANDLER_OUTPUT,
-          "File \"" << filename << "\" not found." << std::endl, this->Quiet);
       }
-      cxml.erase(measurementfile.start(),
-                 measurementfile.end() - measurementfile.start());
-    } else {
-      done = true;
     }
+
+    // Remove this element from content.
+    cmSystemTools::ReplaceString(content, measurement_str.c_str(), "");
   }
 }
 
-void cmCTestTestHandler::SetIncludeRegExp(const char* arg)
+void cmCTestTestHandler::SetIncludeRegExp(const std::string& arg)
 {
   this->IncludeRegExp = arg;
 }
 
-void cmCTestTestHandler::SetExcludeRegExp(const char* arg)
+void cmCTestTestHandler::SetExcludeRegExp(const std::string& arg)
 {
   this->ExcludeRegExp = arg;
 }
 
-void cmCTestTestHandler::SetTestsToRunInformation(const char* in)
+void cmCTestTestHandler::SetTestsToRunInformation(cmValue in)
 {
   if (!in) {
     return;
   }
-  this->TestsToRunString = in;
+  this->TestsToRunString = *in;
   // if the argument is a file, then read it and use the contents as the
   // string
   if (cmSystemTools::FileExists(in)) {
-    cmsys::ifstream fin(in);
+    cmsys::ifstream fin(in->c_str());
     unsigned long filelen = cmSystemTools::FileLength(in);
     auto buff = cm::make_unique<char[]>(filelen + 1);
     fin.getline(buff.get(), filelen);
@@ -2247,7 +2180,7 @@ bool cmCTestTestHandler::SetTestsProperties(
 
             // Ensure we have complete triples otherwise the data is corrupt.
             if (triples.size() % 3 == 0) {
-              cmState state;
+              cmState state(cmState::Unknown);
               rt.Backtrace = cmListFileBacktrace(state.CreateBaseSnapshot());
 
               // the first entry represents the top of the trace so we need to
@@ -2327,6 +2260,8 @@ bool cmCTestTestHandler::SetTestsProperties(
             cmExpandList(val, rt.Depends);
           } else if (key == "ENVIRONMENT"_s) {
             cmExpandList(val, rt.Environment);
+          } else if (key == "ENVIRONMENT_MODIFICATION"_s) {
+            cmExpandList(val, rt.EnvironmentModification);
           } else if (key == "LABELS"_s) {
             std::vector<std::string> Labels = cmExpandedList(val);
             rt.Labels.insert(rt.Labels.end(), Labels.begin(), Labels.end());
index bd51738..3ac05e7 100644 (file)
@@ -22,6 +22,7 @@
 #include "cmCTestResourceSpec.h"
 #include "cmDuration.h"
 #include "cmListFileCache.h"
+#include "cmValue.h"
 
 class cmMakefile;
 class cmXMLWriter;
@@ -65,8 +66,8 @@ public:
   /// them on
   void UseIncludeRegExp();
   void UseExcludeRegExp();
-  void SetIncludeRegExp(const char*);
-  void SetExcludeRegExp(const char*);
+  void SetIncludeRegExp(const std::string&);
+  void SetExcludeRegExp(const std::string&);
 
   void SetMaxIndex(int n) { this->MaxIndex = n; }
   int GetMaxIndex() { return this->MaxIndex; }
@@ -81,7 +82,7 @@ public:
   }
 
   //! pass the -I argument down
-  void SetTestsToRunInformation(const char*);
+  void SetTestsToRunInformation(cmValue);
 
   cmCTestTestHandler();
 
@@ -151,6 +152,7 @@ public:
     // return code of test which will mark test as "not run"
     int SkipReturnCode;
     std::vector<std::string> Environment;
+    std::vector<std::string> EnvironmentModification;
     std::vector<std::string> Labels;
     std::set<std::string> LockedResources;
     std::set<std::string> FixturesSetup;
@@ -177,7 +179,7 @@ public:
     std::string CompletionStatus;
     std::string CustomCompletionStatus;
     std::string Output;
-    std::string DartString;
+    std::string TestMeasurementsOutput;
     int TestCount;
     cmCTestTestProperties* Properties;
   };
@@ -276,9 +278,9 @@ public:
 
 private:
   /**
-   * Generate the Dart compatible output
+   * Write test results in CTest's Test.xml format
    */
-  virtual void GenerateDartOutput(cmXMLWriter& xml);
+  virtual void GenerateCTestXML(cmXMLWriter& xml);
 
   /**
    * Write test results in JUnit XML format
@@ -348,8 +350,7 @@ private:
   cmCTestResourceSpec ResourceSpec;
   std::string ResourceSpecFile;
 
-  void GenerateRegressionImages(cmXMLWriter& xml, const std::string& dart);
-  cmsys::RegularExpression DartStuff1;
+  void RecordCustomTestMeasurements(cmXMLWriter& xml, std::string content);
   void CheckLabelFilter(cmCTestTestProperties& it);
   void CheckLabelFilterExclude(cmCTestTestProperties& it);
   void CheckLabelFilterInclude(cmCTestTestProperties& it);
@@ -358,8 +359,10 @@ private:
   bool UseUnion;
   ListOfTests TestList;
   size_t TotalNumberOfTests;
-  cmsys::RegularExpression DartStuff;
+  cmsys::RegularExpression AllTestMeasurementsRegex;
+  cmsys::RegularExpression SingleTestMeasurementRegex;
   cmsys::RegularExpression CustomCompletionStatusRegex;
+  cmsys::RegularExpression CustomLabelRegex;
 
   std::ostream* LogFile;
 
diff --git a/Source/CTest/cmCTestTestMeasurementXMLParser.cxx b/Source/CTest/cmCTestTestMeasurementXMLParser.cxx
new file mode 100644 (file)
index 0000000..636be24
--- /dev/null
@@ -0,0 +1,26 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include "cmCTestTestMeasurementXMLParser.h"
+
+#include <cstring>
+
+void cmCTestTestMeasurementXMLParser::StartElement(const std::string& name,
+                                                   const char** attributes)
+{
+  this->CharacterData.clear();
+  this->ElementName = name;
+  for (const char** attr = attributes; *attr; attr += 2) {
+    if (strcmp(attr[0], "name") == 0) {
+      this->MeasurementName = attr[1];
+    } else if (strcmp(attr[0], "type") == 0) {
+      this->MeasurementType = attr[1];
+    }
+  }
+}
+
+void cmCTestTestMeasurementXMLParser::CharacterDataHandler(const char* data,
+                                                           int length)
+{
+  this->CharacterData.append(data, length);
+}
diff --git a/Source/CTest/cmCTestTestMeasurementXMLParser.h b/Source/CTest/cmCTestTestMeasurementXMLParser.h
new file mode 100644 (file)
index 0000000..b2c3eb3
--- /dev/null
@@ -0,0 +1,21 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include <string>
+
+#include "cmXMLParser.h"
+
+class cmCTestTestMeasurementXMLParser : public cmXMLParser
+{
+public:
+  cmCTestTestMeasurementXMLParser() {}
+  std::string CharacterData;
+  std::string ElementName;
+  std::string MeasurementName;
+  std::string MeasurementType;
+
+protected:
+  void StartElement(const std::string& name, const char** atts) override;
+  void EndElement(const std::string& /*name*/) override {}
+  void CharacterDataHandler(const char* data, int length) override;
+};
index 797cb01..6655bf7 100644 (file)
@@ -79,7 +79,7 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
     this->SetError("source directory not specified. Please use SOURCE tag");
     return nullptr;
   }
-  handler->SetOption("SourceDirectory", source_dir.c_str());
+  handler->SetOption("SourceDirectory", source_dir);
   handler->SetQuiet(this->Quiet);
   return handler;
 }
index 57cc024..d448c76 100644 (file)
@@ -19,6 +19,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 #include "cmXMLWriter.h"
 
@@ -108,7 +109,7 @@ int cmCTestUpdateHandler::ProcessHandler()
   static_cast<void>(fixLocale);
 
   // Get source dir
-  const char* sourceDirectory = this->GetOption("SourceDirectory");
+  cmValue sourceDirectory = this->GetOption("SourceDirectory");
   if (!sourceDirectory) {
     cmCTestLog(this->CTest, ERROR_MESSAGE,
                "Cannot find SourceDirectory  key in the DartConfiguration.tcl"
@@ -257,7 +258,7 @@ int cmCTestUpdateHandler::ProcessHandler()
   return updated && loadedMods ? numUpdated : -1;
 }
 
-int cmCTestUpdateHandler::DetectVCS(const char* dir)
+int cmCTestUpdateHandler::DetectVCS(const std::string& dir)
 {
   std::string sourceDirectory = dir;
   cmCTestOptionalLog(this->CTest, DEBUG,
index 25bbb2f..70269ea 100644 (file)
@@ -59,6 +59,6 @@ private:
   std::string UpdateCommand;
   int UpdateType;
 
-  int DetectVCS(const char* dir);
+  int DetectVCS(const std::string& dir);
   bool SelectVCS();
 };
index 452d714..423b506 100644 (file)
@@ -10,8 +10,8 @@
 #include "cmsys/Process.h"
 
 #include "cmCTest.h"
-#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmXMLWriter.h"
 
 cmCTestVC::cmCTestVC(cmCTest* ct, std::ostream& log)
index 35f09fd..e9ec09e 100644 (file)
 #include "cmCursesPathWidget.h"
 #include "cmCursesStringWidget.h"
 #include "cmCursesWidget.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmCursesCacheEntryComposite::cmCursesCacheEntryComposite(
   const std::string& key, int labelwidth, int entrywidth)
@@ -49,7 +49,7 @@ cmCursesCacheEntryComposite::cmCursesCacheEntryComposite(
     this->IsNewLabel = cm::make_unique<cmCursesLabelWidget>(1, 1, 1, 1, " ");
   }
 
-  cmProp value = state->GetCacheEntryValue(key);
+  cmValue value = state->GetCacheEntryValue(key);
   assert(value);
   switch (state->GetCacheEntryType(key)) {
     case cmStateEnums::BOOL: {
@@ -72,7 +72,7 @@ cmCursesCacheEntryComposite::cmCursesCacheEntryComposite(
       break;
     }
     case cmStateEnums::STRING: {
-      cmProp stringsProp = state->GetCacheEntryProperty(key, "STRINGS");
+      cmValue stringsProp = state->GetCacheEntryProperty(key, "STRINGS");
       if (stringsProp) {
         auto ow =
           cm::make_unique<cmCursesOptionsWidget>(this->EntryWidth, 1, 1, 1);
index 069c02e..b28c5b7 100644 (file)
 #include "cmCursesStandardIncludes.h"
 #include "cmCursesStringWidget.h"
 #include "cmCursesWidget.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 #include "cmake.h"
 
@@ -162,7 +162,7 @@ void cmCursesMainForm::RePost()
     // If normal mode, count only non-advanced entries
     this->NumberOfVisibleEntries = 0;
     for (cmCursesCacheEntryComposite& entry : this->Entries) {
-      cmProp existingValue =
+      cmValue existingValue =
         this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue());
       bool advanced =
         this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
@@ -183,7 +183,7 @@ void cmCursesMainForm::RePost()
 
   // Assign fields
   for (cmCursesCacheEntryComposite& entry : this->Entries) {
-    cmProp existingValue =
+    cmValue existingValue =
       this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue());
     bool advanced =
       this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
@@ -242,7 +242,7 @@ void cmCursesMainForm::Render(int left, int top, int width, int height)
     // If normal, display only non-advanced entries
     this->NumberOfVisibleEntries = 0;
     for (cmCursesCacheEntryComposite& entry : this->Entries) {
-      cmProp existingValue =
+      cmValue existingValue =
         this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue());
       bool advanced =
         this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
@@ -260,7 +260,7 @@ void cmCursesMainForm::Render(int left, int top, int width, int height)
     bool isNewPage;
     int i = 0;
     for (cmCursesCacheEntryComposite& entry : this->Entries) {
-      cmProp existingValue =
+      cmValue existingValue =
         this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue());
       bool advanced =
         this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
@@ -406,9 +406,9 @@ void cmCursesMainForm::UpdateStatusBar(cm::optional<std::string> message)
     // Get the help string of the current entry
     // and add it to the help string
     auto* cmakeState = this->CMakeInstance->GetState();
-    cmProp existingValue = cmakeState->GetCacheEntryValue(labelValue);
+    cmValue existingValue = cmakeState->GetCacheEntryValue(labelValue);
     if (existingValue) {
-      cmProp help =
+      cmValue help =
         cmakeState->GetCacheEntryProperty(labelValue, "HELPSTRING");
       if (help) {
         bar += *help;
@@ -618,7 +618,7 @@ void cmCursesMainForm::FillCacheManagerFromUI()
 {
   for (cmCursesCacheEntryComposite& entry : this->Entries) {
     const std::string& cacheKey = entry.Key;
-    cmProp existingValue =
+    cmValue existingValue =
       this->CMakeInstance->GetState()->GetCacheEntryValue(cacheKey);
     if (existingValue) {
       std::string oldValue = *existingValue;
@@ -804,9 +804,9 @@ void cmCursesMainForm::HandleInput()
         cmCursesWidget* lbl = reinterpret_cast<cmCursesWidget*>(
           field_userptr(this->Fields[findex - 2]));
         const char* curField = lbl->GetValue();
-        cmProp helpString = nullptr;
+        cmValue helpString = nullptr;
 
-        cmProp existingValue =
+        cmValue existingValue =
           this->CMakeInstance->GetState()->GetCacheEntryValue(curField);
         if (existingValue) {
           helpString = this->CMakeInstance->GetState()->GetCacheEntryProperty(
index 3f3ddde..50e9752 100644 (file)
@@ -600,12 +600,12 @@ static const yytype_int8 yytranslate[] =
 static const yytype_uint8 yyrline[] =
 {
        0,   101,   101,   101,   104,   108,   113,   122,   128,   135,
-     140,   144,   149,   157,   162,   167,   172,   177,   182,   187,
-     192,   197,   201,   205,   209,   213,   214,   219,   219,   219,
-     220,   220,   221,   221,   222,   222,   223,   223,   224,   224,
-     225,   225,   226,   226,   227,   227,   228,   228,   231,   232,
-     233,   234,   235,   236,   237,   238,   239,   240,   241,   242,
-     243,   244,   245,   246,   247
+     140,   144,   149,   161,   166,   171,   176,   181,   186,   191,
+     196,   201,   205,   209,   213,   217,   218,   223,   223,   223,
+     224,   224,   225,   225,   226,   226,   227,   227,   228,   228,
+     229,   229,   230,   230,   231,   231,   232,   232,   235,   236,
+     237,   238,   239,   240,   241,   242,   243,   244,   245,   246,
+     247,   248,   249,   250,   251
 };
 #endif
 
@@ -1747,142 +1747,146 @@ yyreduce:
       cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
       cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
     }
+    if (cmsysString_strcasecmp((yyvsp[-4].string), "intrinsic") == 0) {
+      cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+      cmFortranParser_RuleUseIntrinsic(parser, (yyvsp[-2].string));
+    }
     free((yyvsp[-4].string));
     free((yyvsp[-2].string));
   }
-#line 1754 "cmFortranParser.cxx"
+#line 1758 "cmFortranParser.cxx"
     break;
 
   case 13: /* stmt: INCLUDE STRING other EOSTMT  */
-#line 157 "cmFortranParser.y"
+#line 161 "cmFortranParser.y"
                               {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1764 "cmFortranParser.cxx"
+#line 1768 "cmFortranParser.cxx"
     break;
 
   case 14: /* stmt: CPP_LINE_DIRECTIVE STRING other EOSTMT  */
-#line 162 "cmFortranParser.y"
+#line 166 "cmFortranParser.y"
                                          {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleLineDirective(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1774 "cmFortranParser.cxx"
+#line 1778 "cmFortranParser.cxx"
     break;
 
   case 15: /* stmt: CPP_INCLUDE_ANGLE other EOSTMT  */
-#line 167 "cmFortranParser.y"
+#line 171 "cmFortranParser.y"
                                  {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1784 "cmFortranParser.cxx"
+#line 1788 "cmFortranParser.cxx"
     break;
 
   case 16: /* stmt: include STRING other EOSTMT  */
-#line 172 "cmFortranParser.y"
+#line 176 "cmFortranParser.y"
                               {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1794 "cmFortranParser.cxx"
+#line 1798 "cmFortranParser.cxx"
     break;
 
   case 17: /* stmt: define WORD other EOSTMT  */
-#line 177 "cmFortranParser.y"
+#line 181 "cmFortranParser.y"
                            {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleDefine(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1804 "cmFortranParser.cxx"
+#line 1808 "cmFortranParser.cxx"
     break;
 
   case 18: /* stmt: undef WORD other EOSTMT  */
-#line 182 "cmFortranParser.y"
+#line 186 "cmFortranParser.y"
                           {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleUndef(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1814 "cmFortranParser.cxx"
+#line 1818 "cmFortranParser.cxx"
     break;
 
   case 19: /* stmt: ifdef WORD other EOSTMT  */
-#line 187 "cmFortranParser.y"
+#line 191 "cmFortranParser.y"
                           {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleIfdef(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1824 "cmFortranParser.cxx"
+#line 1828 "cmFortranParser.cxx"
     break;
 
   case 20: /* stmt: ifndef WORD other EOSTMT  */
-#line 192 "cmFortranParser.y"
+#line 196 "cmFortranParser.y"
                            {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleIfndef(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1834 "cmFortranParser.cxx"
+#line 1838 "cmFortranParser.cxx"
     break;
 
   case 21: /* stmt: if other EOSTMT  */
-#line 197 "cmFortranParser.y"
+#line 201 "cmFortranParser.y"
                   {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleIf(parser);
   }
-#line 1843 "cmFortranParser.cxx"
+#line 1847 "cmFortranParser.cxx"
     break;
 
   case 22: /* stmt: elif other EOSTMT  */
-#line 201 "cmFortranParser.y"
+#line 205 "cmFortranParser.y"
                     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleElif(parser);
   }
-#line 1852 "cmFortranParser.cxx"
+#line 1856 "cmFortranParser.cxx"
     break;
 
   case 23: /* stmt: else other EOSTMT  */
-#line 205 "cmFortranParser.y"
+#line 209 "cmFortranParser.y"
                     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleElse(parser);
   }
-#line 1861 "cmFortranParser.cxx"
+#line 1865 "cmFortranParser.cxx"
     break;
 
   case 24: /* stmt: endif other EOSTMT  */
-#line 209 "cmFortranParser.y"
+#line 213 "cmFortranParser.y"
                      {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleEndif(parser);
   }
-#line 1870 "cmFortranParser.cxx"
+#line 1874 "cmFortranParser.cxx"
     break;
 
   case 48: /* misc_code: WORD  */
-#line 231 "cmFortranParser.y"
+#line 235 "cmFortranParser.y"
                       { free ((yyvsp[0].string)); }
-#line 1876 "cmFortranParser.cxx"
+#line 1880 "cmFortranParser.cxx"
     break;
 
   case 55: /* misc_code: STRING  */
-#line 238 "cmFortranParser.y"
+#line 242 "cmFortranParser.y"
                       { free ((yyvsp[0].string)); }
-#line 1882 "cmFortranParser.cxx"
+#line 1886 "cmFortranParser.cxx"
     break;
 
 
-#line 1886 "cmFortranParser.cxx"
+#line 1890 "cmFortranParser.cxx"
 
       default: break;
     }
@@ -2107,6 +2111,6 @@ yyreturn:
   return yyresult;
 }
 
-#line 250 "cmFortranParser.y"
+#line 254 "cmFortranParser.y"
 
 /* End of grammar */
index a3e1c24..8ef1903 100644 (file)
@@ -151,6 +151,10 @@ stmt:
       cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
       cmFortranParser_RuleUse(parser, $5);
     }
+    if (cmsysString_strcasecmp($3, "intrinsic") == 0) {
+      cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
+      cmFortranParser_RuleUseIntrinsic(parser, $5);
+    }
     free($3);
     free($5);
   }
index c556049..8ffa3e7 100644 (file)
 #include <QTranslator>
 #include <QtPlugin>
 
-// FIXME(#23565): Qt6 has QTextCodec in Core5Compat, but using its
-// `setCodecForLocale` does not make cmake-gui support non-ASCII chars
-// on Windows.  For now we only support them with Qt5.  How do we support
-// them with Qt6, preferably without Core5Compat?
-#if defined(Q_OS_WIN) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
-#  include <QTextCodec>
-#  define CMAKE_HAVE_QTEXTCODEC
-#endif
-
 #include "cmsys/CommandLineArguments.hxx"
 #include "cmsys/Encoding.hxx"
 #include "cmsys/SystemTools.hxx"
@@ -133,11 +124,6 @@ int main(int argc, char** argv)
 
   setlocale(LC_NUMERIC, "C");
 
-#ifdef CMAKE_HAVE_QTEXTCODEC
-  QTextCodec* utf8_codec = QTextCodec::codecForName("UTF-8");
-  QTextCodec::setCodecForLocale(utf8_codec);
-#endif
-
   // tell the cmake library where cmake is
   QDir cmExecDir(QApplication::applicationDirPath());
 #if defined(Q_OS_MAC)
index e6faef4..8ab8656 100644 (file)
@@ -122,26 +122,26 @@ void QCMake::setBinaryDirectory(const QString& _dir)
 
     QCMakePropertyList props = this->properties();
     emit this->propertiesChanged(props);
-    cmProp homeDir = state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
+    cmValue homeDir = state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
     if (homeDir) {
       setSourceDirectory(QString::fromLocal8Bit(homeDir->c_str()));
     }
-    cmProp gen = state->GetCacheEntryValue("CMAKE_GENERATOR");
+    cmValue gen = state->GetCacheEntryValue("CMAKE_GENERATOR");
     if (gen) {
-      const std::string* extraGen =
+      cmValue extraGen =
         state->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
       std::string curGen =
-        cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
-          *gen, extraGen ? *extraGen : "");
+        cmExternalMakefileProjectGenerator::CreateFullGeneratorName(*gen,
+                                                                    *extraGen);
       this->setGenerator(QString::fromLocal8Bit(curGen.c_str()));
     }
 
-    cmProp platform = state->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM");
+    cmValue platform = state->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM");
     if (platform) {
       this->setPlatform(QString::fromLocal8Bit(platform->c_str()));
     }
 
-    cmProp toolset = state->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET");
+    cmValue toolset = state->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET");
     if (toolset) {
       this->setToolset(QString::fromLocal8Bit(toolset->c_str()));
     }
@@ -396,11 +396,11 @@ QCMakePropertyList QCMake::properties() const
       continue;
     }
 
-    cmProp cachedValue = state->GetCacheEntryValue(key);
+    cmValue cachedValue = state->GetCacheEntryValue(key);
 
     QCMakeProperty prop;
     prop.Key = QString::fromLocal8Bit(key.c_str());
-    if (cmProp hs = state->GetCacheEntryProperty(key, "HELPSTRING")) {
+    if (cmValue hs = state->GetCacheEntryProperty(key, "HELPSTRING")) {
       prop.Help = QString::fromLocal8Bit(hs->c_str());
     }
     prop.Value = QString::fromLocal8Bit(cachedValue->c_str());
@@ -414,7 +414,7 @@ QCMakePropertyList QCMake::properties() const
       prop.Type = QCMakeProperty::FILEPATH;
     } else if (t == cmStateEnums::STRING) {
       prop.Type = QCMakeProperty::STRING;
-      cmProp stringsProperty = state->GetCacheEntryProperty(key, "STRINGS");
+      cmValue stringsProperty = state->GetCacheEntryProperty(key, "STRINGS");
       if (stringsProperty) {
         prop.Strings =
           QString::fromLocal8Bit(stringsProperty->c_str()).split(";");
@@ -550,17 +550,14 @@ void QCMake::loadPresets()
     }
 
     QCMakePreset preset;
-    preset.name = std::move(QString::fromLocal8Bit(p.Name.data()));
-    preset.displayName =
-      std::move(QString::fromLocal8Bit(p.DisplayName.data()));
-    preset.description =
-      std::move(QString::fromLocal8Bit(p.Description.data()));
-    preset.generator = std::move(QString::fromLocal8Bit(p.Generator.data()));
-    preset.architecture =
-      std::move(QString::fromLocal8Bit(p.Architecture.data()));
+    preset.name = QString::fromLocal8Bit(p.Name.data());
+    preset.displayName = QString::fromLocal8Bit(p.DisplayName.data());
+    preset.description = QString::fromLocal8Bit(p.Description.data());
+    preset.generator = QString::fromLocal8Bit(p.Generator.data());
+    preset.architecture = QString::fromLocal8Bit(p.Architecture.data());
     preset.setArchitecture = !p.ArchitectureStrategy ||
       p.ArchitectureStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set;
-    preset.toolset = std::move(QString::fromLocal8Bit(p.Toolset.data()));
+    preset.toolset = QString::fromLocal8Bit(p.Toolset.data());
     preset.setToolset = !p.ToolsetStrategy ||
       p.ToolsetStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set;
     preset.enabled = it.Expanded && it.Expanded->ConditionResult &&
index 92e04e4..a5d1f6a 100644 (file)
@@ -12,6 +12,7 @@
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 
 bool cmAddLibraryCommand(std::vector<std::string> const& args,
                          cmExecutionStatus& status)
index 205c1c7..a0d5732 100644 (file)
@@ -140,7 +140,7 @@ bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args,
   test->SetOldStyle(false);
   test->SetCommand(command);
   if (!working_directory.empty()) {
-    test->SetProperty("WORKING_DIRECTORY", working_directory.c_str());
+    test->SetProperty("WORKING_DIRECTORY", working_directory);
   }
   test->SetCommandExpandLists(command_expand_lists);
   mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test, configurations));
index c192e2a..a1830f9 100644 (file)
@@ -60,6 +60,10 @@ class cmListFileBacktrace;
 using cmBacktraceRange =
   cmRange<std::vector<cmListFileBacktrace>::const_iterator>;
 
+template <typename T>
+class BT;
+using cmBTStringRange = cmRange<std::vector<BT<std::string>>::const_iterator>;
+
 template <typename Range>
 typename Range::const_iterator cmRemoveN(Range& r, size_t n)
 {
@@ -133,7 +137,13 @@ ForwardIterator cmRemoveDuplicates(ForwardIterator first, ForwardIterator last)
 }
 
 template <typename Range>
-typename Range::const_iterator cmRemoveDuplicates(Range& r)
+typename Range::iterator cmRemoveDuplicates(Range& r)
+{
+  return cmRemoveDuplicates(r.begin(), r.end());
+}
+
+template <typename Range>
+typename Range::const_iterator cmRemoveDuplicates(Range const& r)
 {
   return cmRemoveDuplicates(r.begin(), r.end());
 }
index 54b2998..9e0d80c 100644 (file)
@@ -250,6 +250,9 @@ cmArchiveWrite::cmArchiveWrite(std::ostream& os, Compress c,
 
 bool cmArchiveWrite::Open()
 {
+  if (!this->Error.empty()) {
+    return false;
+  }
   if (archive_write_open(
         this->Archive, this, nullptr,
         reinterpret_cast<archive_write_callback*>(&Callback::Write),
index 99707a3..a69c00d 100644 (file)
@@ -11,6 +11,7 @@
 #include <cmsys/RegularExpression.hxx>
 
 #include "cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h"
+#include "cmELF.h"
 #include "cmLDConfigLDConfigTool.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
-#ifdef CMake_USE_ELF_PARSER
-#  include "cmELF.h"
-#endif
-
 static std::string ReplaceOrigin(const std::string& rpath,
                                  const std::string& origin)
 {
@@ -91,7 +88,6 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies(
 {
   std::vector<std::string> parentRpaths;
 
-#ifdef CMake_USE_ELF_PARSER
   cmELF elf(file.c_str());
   if (!elf) {
     return false;
@@ -106,7 +102,6 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies(
       this->Machine = elf.GetMachine();
     }
   }
-#endif
 
   return this->ScanDependencies(file, parentRpaths);
 }
@@ -175,15 +170,11 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies(
 namespace {
 bool FileHasArchitecture(const char* filename, std::uint16_t machine)
 {
-#ifdef CMake_USE_ELF_PARSER
   cmELF elf(filename);
   if (!elf) {
     return false;
   }
   return machine == 0 || machine == elf.GetMachine();
-#else
-  return true;
-#endif
 }
 }
 
index 47f77d8..c064377 100644 (file)
@@ -5,6 +5,8 @@
 
 #include <sstream>
 #include <string>
+#include <type_traits>
+#include <utility>
 #include <vector>
 
 #include <cm/memory>
@@ -52,6 +54,26 @@ bool cmBinUtilsMacOSMachOLinker::Prepare()
   return true;
 }
 
+auto cmBinUtilsMacOSMachOLinker::GetFileInfo(std::string const& file)
+  -> const FileInfo*
+{
+  // Memoize processed rpaths and library dependencies to reduce the number
+  // of calls to otool, especially in the case of heavily recursive libraries
+  auto iter = ScannedFileInfo.find(file);
+  if (iter != ScannedFileInfo.end()) {
+    return &iter->second;
+  }
+
+  FileInfo file_info;
+  if (!this->Tool->GetFileInfo(file, file_info.libs, file_info.rpaths)) {
+    // Call to otool failed
+    return nullptr;
+  }
+
+  auto iter_inserted = ScannedFileInfo.insert({ file, std::move(file_info) });
+  return &iter_inserted.first->second;
+}
+
 bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
   std::string const& file, cmStateEnums::TargetType type)
 {
@@ -65,12 +87,12 @@ bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
   if (!executableFile.empty()) {
     executablePath = cmSystemTools::GetFilenamePath(executableFile);
   }
-  std::vector<std::string> libs;
-  std::vector<std::string> rpaths;
-  if (!this->Tool->GetFileInfo(file, libs, rpaths)) {
+  const FileInfo* file_info = this->GetFileInfo(file);
+  if (file_info == nullptr) {
     return false;
   }
-  return this->ScanDependencies(file, libs, rpaths, executablePath);
+  return this->ScanDependencies(file, file_info->libs, file_info->rpaths,
+                                executablePath);
 }
 
 bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
@@ -98,14 +120,16 @@ bool cmBinUtilsMacOSMachOLinker::GetFileDependencies(
             !IsMissingSystemDylib(path)) {
           auto filename = cmSystemTools::GetFilenameName(path);
           bool unique;
-          std::vector<std::string> libs;
-          std::vector<std::string> depRpaths;
-          if (!this->Tool->GetFileInfo(path, libs, depRpaths)) {
+          const FileInfo* dep_file_info = this->GetFileInfo(path);
+          if (dep_file_info == nullptr) {
             return false;
           }
-          this->Archive->AddResolvedPath(filename, path, unique, depRpaths);
+
+          this->Archive->AddResolvedPath(filename, path, unique,
+                                         dep_file_info->rpaths);
           if (unique &&
-              !this->ScanDependencies(path, libs, depRpaths, executablePath)) {
+              !this->ScanDependencies(path, dep_file_info->libs,
+                                      dep_file_info->rpaths, executablePath)) {
             return false;
           }
         }
index eae23cc..ac1177b 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <memory>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "cmBinUtilsLinker.h"
@@ -24,7 +25,16 @@ public:
                         cmStateEnums::TargetType type) override;
 
 private:
+  struct FileInfo
+  {
+    std::vector<std::string> libs;
+    std::vector<std::string> rpaths;
+  };
+
   std::unique_ptr<cmBinUtilsMacOSMachOGetRuntimeDependenciesTool> Tool;
+  std::unordered_map<std::string, FileInfo> ScannedFileInfo;
+
+  const FileInfo* GetFileInfo(std::string const& file);
 
   bool ScanDependencies(std::string const& file,
                         std::vector<std::string> const& libs,
index 56b080a..415a124 100644 (file)
@@ -6,10 +6,10 @@
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 namespace {
 
@@ -102,7 +102,7 @@ bool TwoArgsSignature(std::vector<std::string> const& args,
   cmMakefile& mf = status.GetMakefile();
 
   std::string const& define = args[0];
-  cmProp cacheValue = mf.GetDefinition(define);
+  cmValue cacheValue = mf.GetDefinition(define);
 
   std::string configType;
   if (!cmSystemTools::GetEnv("CMAKE_CONFIG_TYPE", configType) ||
index f9b8f8f..20d6089 100644 (file)
@@ -8,9 +8,9 @@
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 bool cmBuildNameCommand(std::vector<std::string> const& args,
                         cmExecutionStatus& status)
@@ -20,7 +20,7 @@ bool cmBuildNameCommand(std::vector<std::string> const& args,
     return false;
   }
   cmMakefile& mf = status.GetMakefile();
-  cmProp cacheValue = mf.GetDefinition(args[0]);
+  cmValue cacheValue = mf.GetDefinition(args[0]);
   if (cacheValue) {
     // do we need to correct the value?
     cmsys::RegularExpression reg("[()/]");
index 0550568..3922c56 100644 (file)
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCMakeHostSystemInformationCommand.h"
 
-#include <cstddef>
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <initializer_list>
+#include <map>
+#include <string>
+#include <type_traits>
+#include <utility>
 
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
 #include "cmsys/SystemInformation.hxx"
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
 
-#if defined(_WIN32)
+#ifdef _WIN32
 #  include "cmAlgorithms.h"
 #  include "cmGlobalGenerator.h"
+#  include "cmGlobalVisualStudio10Generator.h"
 #  include "cmGlobalVisualStudioVersionedGenerator.h"
-#  include "cmSystemTools.h"
 #  include "cmVSSetupHelper.h"
 #  define HAVE_VS_SETUP_HELPER
 #endif
 
 namespace {
-bool GetValue(cmExecutionStatus& status, cmsys::SystemInformation& info,
-              std::string const& key, std::string& value);
-std::string ValueToString(size_t value);
-std::string ValueToString(const char* value);
-std::string ValueToString(std::string const& value);
-}
+std::string const DELIM[2] = { {}, ";" };
 
-// cmCMakeHostSystemInformation
-bool cmCMakeHostSystemInformationCommand(std::vector<std::string> const& args,
-                                         cmExecutionStatus& status)
+// BEGIN Private functions
+std::string ValueToString(std::size_t const value)
 {
-  size_t current_index = 0;
-
-  if (args.size() < (current_index + 2) || args[current_index] != "RESULT") {
-    status.SetError("missing RESULT specification.");
-    return false;
-  }
-
-  std::string const& variable = args[current_index + 1];
-  current_index += 2;
-
-  if (args.size() < (current_index + 2) || args[current_index] != "QUERY") {
-    status.SetError("missing QUERY specification");
-    return false;
-  }
-
-  cmsys::SystemInformation info;
-  info.RunCPUCheck();
-  info.RunOSCheck();
-  info.RunMemoryCheck();
-
-  std::string result_list;
-  for (size_t i = current_index + 1; i < args.size(); ++i) {
-    std::string const& key = args[i];
-    if (i != current_index + 1) {
-      result_list += ";";
-    }
-    std::string value;
-    if (!GetValue(status, info, key, value)) {
-      return false;
-    }
-    result_list += value;
-  }
-
-  status.GetMakefile().AddDefinition(variable, result_list);
+  return std::to_string(value);
+}
 
-  return true;
+std::string ValueToString(const char* const value)
+{
+  return value ? value : std::string{};
 }
 
-namespace {
+std::string ValueToString(std::string const& value)
+{
+  return value;
+}
 
-bool GetValue(cmExecutionStatus& status, cmsys::SystemInformation& info,
-              std::string const& key, std::string& value)
+cm::optional<std::string> GetValue(cmsys::SystemInformation& info,
+                                   std::string const& key)
 {
-  if (key == "NUMBER_OF_LOGICAL_CORES") {
-    value = ValueToString(info.GetNumberOfLogicalCPU());
-  } else if (key == "NUMBER_OF_PHYSICAL_CORES") {
-    value = ValueToString(info.GetNumberOfPhysicalCPU());
-  } else if (key == "HOSTNAME") {
-    value = ValueToString(info.GetHostname());
-  } else if (key == "FQDN") {
-    value = ValueToString(info.GetFullyQualifiedDomainName());
-  } else if (key == "TOTAL_VIRTUAL_MEMORY") {
-    value = ValueToString(info.GetTotalVirtualMemory());
-  } else if (key == "AVAILABLE_VIRTUAL_MEMORY") {
-    value = ValueToString(info.GetAvailableVirtualMemory());
-  } else if (key == "TOTAL_PHYSICAL_MEMORY") {
-    value = ValueToString(info.GetTotalPhysicalMemory());
-  } else if (key == "AVAILABLE_PHYSICAL_MEMORY") {
-    value = ValueToString(info.GetAvailablePhysicalMemory());
-  } else if (key == "IS_64BIT") {
-    value = ValueToString(info.Is64Bits());
-  } else if (key == "HAS_FPU") {
-    value = ValueToString(
+  if (key == "NUMBER_OF_LOGICAL_CORES"_s) {
+    return ValueToString(info.GetNumberOfLogicalCPU());
+  }
+  if (key == "NUMBER_OF_PHYSICAL_CORES"_s) {
+    return ValueToString(info.GetNumberOfPhysicalCPU());
+  }
+  if (key == "HOSTNAME"_s) {
+    return ValueToString(info.GetHostname());
+  }
+  if (key == "FQDN"_s) {
+    return ValueToString(info.GetFullyQualifiedDomainName());
+  }
+  if (key == "TOTAL_VIRTUAL_MEMORY"_s) {
+    return ValueToString(info.GetTotalVirtualMemory());
+  }
+  if (key == "AVAILABLE_VIRTUAL_MEMORY"_s) {
+    return ValueToString(info.GetAvailableVirtualMemory());
+  }
+  if (key == "TOTAL_PHYSICAL_MEMORY"_s) {
+    return ValueToString(info.GetTotalPhysicalMemory());
+  }
+  if (key == "AVAILABLE_PHYSICAL_MEMORY"_s) {
+    return ValueToString(info.GetAvailablePhysicalMemory());
+  }
+  if (key == "IS_64BIT"_s) {
+    return ValueToString(info.Is64Bits());
+  }
+  if (key == "HAS_FPU"_s) {
+    return ValueToString(
       info.DoesCPUSupportFeature(cmsys::SystemInformation::CPU_FEATURE_FPU));
-  } else if (key == "HAS_MMX") {
-    value = ValueToString(
+  }
+  if (key == "HAS_MMX"_s) {
+    return ValueToString(
       info.DoesCPUSupportFeature(cmsys::SystemInformation::CPU_FEATURE_MMX));
-  } else if (key == "HAS_MMX_PLUS") {
-    value = ValueToString(info.DoesCPUSupportFeature(
+  }
+  if (key == "HAS_MMX_PLUS"_s) {
+    return ValueToString(info.DoesCPUSupportFeature(
       cmsys::SystemInformation::CPU_FEATURE_MMX_PLUS));
-  } else if (key == "HAS_SSE") {
-    value = ValueToString(
+  }
+  if (key == "HAS_SSE"_s) {
+    return ValueToString(
       info.DoesCPUSupportFeature(cmsys::SystemInformation::CPU_FEATURE_SSE));
-  } else if (key == "HAS_SSE2") {
-    value = ValueToString(
+  }
+  if (key == "HAS_SSE2"_s) {
+    return ValueToString(
       info.DoesCPUSupportFeature(cmsys::SystemInformation::CPU_FEATURE_SSE2));
-  } else if (key == "HAS_SSE_FP") {
-    value = ValueToString(info.DoesCPUSupportFeature(
+  }
+  if (key == "HAS_SSE_FP"_s) {
+    return ValueToString(info.DoesCPUSupportFeature(
       cmsys::SystemInformation::CPU_FEATURE_SSE_FP));
-  } else if (key == "HAS_SSE_MMX") {
-    value = ValueToString(info.DoesCPUSupportFeature(
+  }
+  if (key == "HAS_SSE_MMX"_s) {
+    return ValueToString(info.DoesCPUSupportFeature(
       cmsys::SystemInformation::CPU_FEATURE_SSE_MMX));
-  } else if (key == "HAS_AMD_3DNOW") {
-    value = ValueToString(info.DoesCPUSupportFeature(
+  }
+  if (key == "HAS_AMD_3DNOW"_s) {
+    return ValueToString(info.DoesCPUSupportFeature(
       cmsys::SystemInformation::CPU_FEATURE_AMD_3DNOW));
-  } else if (key == "HAS_AMD_3DNOW_PLUS") {
-    value = ValueToString(info.DoesCPUSupportFeature(
+  }
+  if (key == "HAS_AMD_3DNOW_PLUS"_s) {
+    return ValueToString(info.DoesCPUSupportFeature(
       cmsys::SystemInformation::CPU_FEATURE_AMD_3DNOW_PLUS));
-  } else if (key == "HAS_IA64") {
-    value = ValueToString(
+  }
+  if (key == "HAS_IA64"_s) {
+    return ValueToString(
       info.DoesCPUSupportFeature(cmsys::SystemInformation::CPU_FEATURE_IA64));
-  } else if (key == "HAS_SERIAL_NUMBER") {
-    value = ValueToString(info.DoesCPUSupportFeature(
+  }
+  if (key == "HAS_SERIAL_NUMBER"_s) {
+    return ValueToString(info.DoesCPUSupportFeature(
       cmsys::SystemInformation::CPU_FEATURE_SERIALNUMBER));
-  } else if (key == "PROCESSOR_NAME") {
-    value = ValueToString(info.GetExtendedProcessorName());
-  } else if (key == "PROCESSOR_DESCRIPTION") {
-    value = info.GetCPUDescription();
-  } else if (key == "PROCESSOR_SERIAL_NUMBER") {
-    value = ValueToString(info.GetProcessorSerialNumber());
-  } else if (key == "OS_NAME") {
-    value = ValueToString(info.GetOSName());
-  } else if (key == "OS_RELEASE") {
-    value = ValueToString(info.GetOSRelease());
-  } else if (key == "OS_VERSION") {
-    value = ValueToString(info.GetOSVersion());
-  } else if (key == "OS_PLATFORM") {
-    value = ValueToString(info.GetOSPlatform());
-#ifdef HAVE_VS_SETUP_HELPER
-  } else if (key == "VS_15_DIR") {
-    // If generating for the VS 15 IDE, use the same instance.
-    cmGlobalGenerator* gg = status.GetMakefile().GetGlobalGenerator();
-    if (cmHasLiteralPrefix(gg->GetName(), "Visual Studio 15 ")) {
-      cmGlobalVisualStudioVersionedGenerator* vs15gen =
-        static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
-      if (vs15gen->GetVSInstance(value)) {
-        return true;
-      }
+  }
+  if (key == "PROCESSOR_NAME"_s) {
+    return ValueToString(info.GetExtendedProcessorName());
+  }
+  if (key == "PROCESSOR_DESCRIPTION"_s) {
+    return info.GetCPUDescription();
+  }
+  if (key == "PROCESSOR_SERIAL_NUMBER"_s) {
+    return ValueToString(info.GetProcessorSerialNumber());
+  }
+  if (key == "OS_NAME"_s) {
+    return ValueToString(info.GetOSName());
+  }
+  if (key == "OS_RELEASE"_s) {
+    return ValueToString(info.GetOSRelease());
+  }
+  if (key == "OS_VERSION"_s) {
+    return ValueToString(info.GetOSVersion());
+  }
+  if (key == "OS_PLATFORM"_s) {
+    return ValueToString(info.GetOSPlatform());
+  }
+  return {};
+}
+
+cm::optional<std::pair<std::string, std::string>> ParseOSReleaseLine(
+  std::string const& line)
+{
+  std::string key;
+  std::string value;
+
+  char prev = 0;
+  enum ParserState
+  {
+    PARSE_KEY_1ST,
+    PARSE_KEY,
+    FOUND_EQ,
+    PARSE_SINGLE_QUOTE_VALUE,
+    PARSE_DBL_QUOTE_VALUE,
+    PARSE_VALUE,
+    IGNORE_REST
+  } state = PARSE_KEY_1ST;
+
+  for (auto ch : line) {
+    switch (state) {
+      case PARSE_KEY_1ST:
+        if (std::isalpha(ch) || ch == '_') {
+          key += ch;
+          state = PARSE_KEY;
+        } else if (!std::isspace(ch)) {
+          state = IGNORE_REST;
+        }
+        break;
+
+      case PARSE_KEY:
+        if (ch == '=') {
+          state = FOUND_EQ;
+        } else if (std::isalnum(ch) || ch == '_') {
+          key += ch;
+        } else {
+          state = IGNORE_REST;
+        }
+        break;
+
+      case FOUND_EQ:
+        switch (ch) {
+          case '\'':
+            state = PARSE_SINGLE_QUOTE_VALUE;
+            break;
+          case '"':
+            state = PARSE_DBL_QUOTE_VALUE;
+            break;
+          case '#':
+          case '\\':
+            state = IGNORE_REST;
+            break;
+          default:
+            value += ch;
+            state = PARSE_VALUE;
+        }
+        break;
+
+      case PARSE_SINGLE_QUOTE_VALUE:
+        if (ch == '\'') {
+          if (prev != '\\') {
+            state = IGNORE_REST;
+          } else {
+            assert(!value.empty());
+            value[value.size() - 1] = ch;
+          }
+        } else {
+          value += ch;
+        }
+        break;
+
+      case PARSE_DBL_QUOTE_VALUE:
+        if (ch == '"') {
+          if (prev != '\\') {
+            state = IGNORE_REST;
+          } else {
+            assert(!value.empty());
+            value[value.size() - 1] = ch;
+          }
+        } else {
+          value += ch;
+        }
+        break;
+
+      case PARSE_VALUE:
+        if (ch == '#' || std::isspace(ch)) {
+          state = IGNORE_REST;
+        } else {
+          value += ch;
+        }
+        break;
+
+      default:
+        // Unexpected os-release parser state!
+        state = IGNORE_REST;
+        break;
     }
 
-    // Otherwise, find a VS 15 instance ourselves.
-    cmVSSetupAPIHelper vsSetupAPIHelper(15);
-    if (vsSetupAPIHelper.GetVSInstanceInfo(value)) {
-      cmSystemTools::ConvertToUnixSlashes(value);
+    if (state == IGNORE_REST) {
+      break;
     }
-  } else if (key == "VS_16_DIR") {
-    // If generating for the VS 16 IDE, use the same instance.
-    cmGlobalGenerator* gg = status.GetMakefile().GetGlobalGenerator();
-    if (cmHasLiteralPrefix(gg->GetName(), "Visual Studio 16 ")) {
-      cmGlobalVisualStudioVersionedGenerator* vs16gen =
-        static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
-      if (vs16gen->GetVSInstance(value)) {
-        return true;
+    prev = ch;
+  }
+  if (!(key.empty() || value.empty())) {
+    return std::make_pair(key, value);
+  }
+  return {};
+}
+
+std::map<std::string, std::string> GetOSReleaseVariables(
+  cmExecutionStatus& status)
+{
+  auto& makefile = status.GetMakefile();
+  const auto& sysroot = makefile.GetSafeDefinition("CMAKE_SYSROOT");
+
+  std::map<std::string, std::string> data;
+  // Based on
+  // https://www.freedesktop.org/software/systemd/man/os-release.html
+  for (auto name : { "/etc/os-release"_s, "/usr/lib/os-release"_s }) {
+    const auto& filename = cmStrCat(sysroot, name);
+    if (cmSystemTools::FileExists(filename)) {
+      cmsys::ifstream fin(filename.c_str());
+      for (std::string line; !std::getline(fin, line).fail();) {
+        auto kv = ParseOSReleaseLine(line);
+        if (kv.has_value()) {
+          data.emplace(kv.value());
+        }
       }
+      break;
+    }
+  }
+  // Got smth?
+  if (!data.empty()) {
+    return data;
+  }
+
+  // Ugh, it could be some pre-os-release distro.
+  // Lets try some fallback getters.
+  // See also:
+  //  - http://linuxmafia.com/faq/Admin/release-files.html
+
+  // 1. CMake provided
+  cmsys::Glob gl;
+  std::vector<std::string> scripts;
+  auto const findExpr = cmStrCat(cmSystemTools::GetCMakeRoot(),
+                                 "/Modules/Internal/OSRelease/*.cmake");
+  if (gl.FindFiles(findExpr)) {
+    scripts = gl.GetFiles();
+  }
+
+  // 2. User provided (append to the CMake prvided)
+  makefile.GetDefExpandList("CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTS", scripts);
+
+  // Filter out files that are not in format `NNN-name.cmake`
+  auto checkName = [](std::string const& filepath) -> bool {
+    auto const& filename = cmSystemTools::GetFilenameName(filepath);
+    // NOTE Minimum filename length expected:
+    //   NNN-<at-least-one-char-name>.cmake  --> 11
+    return (filename.size() < 11) || !std::isdigit(filename[0]) ||
+      !std::isdigit(filename[1]) || !std::isdigit(filename[2]) ||
+      filename[3] != '-';
+  };
+  scripts.erase(std::remove_if(scripts.begin(), scripts.end(), checkName),
+                scripts.end());
+
+  // Make sure scripts are running in desired order
+  std::sort(scripts.begin(), scripts.end(),
+            [](std::string const& lhs, std::string const& rhs) -> bool {
+              long lhs_order;
+              cmStrToLong(cmSystemTools::GetFilenameName(lhs).substr(0u, 3u),
+                          &lhs_order);
+              long rhs_order;
+              cmStrToLong(cmSystemTools::GetFilenameName(rhs).substr(0u, 3u),
+                          &rhs_order);
+              return lhs_order < rhs_order;
+            });
+
+  // Name of the variable to put the results
+  auto const result_variable = "CMAKE_GET_OS_RELEASE_FALLBACK_RESULT"_s;
+
+  for (auto const& script : scripts) {
+    // Unset the result variable
+    makefile.RemoveDefinition(result_variable.data());
+
+    // include FATAL_ERROR and ERROR in the return status
+    if (!makefile.ReadListFile(script) ||
+        cmSystemTools::GetErrorOccuredFlag()) {
+      // Ok, no worries... go try the next script.
+      continue;
     }
 
-    // Otherwise, find a VS 16 instance ourselves.
-    cmVSSetupAPIHelper vsSetupAPIHelper(16);
-    if (vsSetupAPIHelper.GetVSInstanceInfo(value)) {
-      cmSystemTools::ConvertToUnixSlashes(value);
+    std::vector<std::string> variables;
+    if (!makefile.GetDefExpandList(result_variable.data(), variables)) {
+      // Heh, this script didn't found anything... go try the next one.
+      continue;
     }
-  } else if (key == "VS_17_DIR") {
-    // If generating for the VS 17 IDE, use the same instance.
-    cmGlobalGenerator* gg = status.GetMakefile().GetGlobalGenerator();
-    if (cmHasLiteralPrefix(gg->GetName(), "Visual Studio 17 ")) {
-      cmGlobalVisualStudioVersionedGenerator* vs17gen =
-        static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
-      if (vs17gen->GetVSInstance(value)) {
-        return true;
+
+    for (auto const& variable : variables) {
+      auto value = makefile.GetSafeDefinition(variable);
+      makefile.RemoveDefinition(variable);
+
+      if (!cmHasPrefix(variable, cmStrCat(result_variable, '_'))) {
+        // Ignore unknown variable set by the script
+        continue;
       }
+
+      auto key = variable.substr(result_variable.size() + 1,
+                                 variable.size() - result_variable.size() - 1);
+      data.emplace(std::move(key), std::move(value));
     }
 
-    // Otherwise, find a VS 17 instance ourselves.
-    cmVSSetupAPIHelper vsSetupAPIHelper(17);
-    if (vsSetupAPIHelper.GetVSInstanceInfo(value)) {
-      cmSystemTools::ConvertToUnixSlashes(value);
+    // Try 'till some script can get anything
+    if (!data.empty()) {
+      data.emplace("USED_FALLBACK_SCRIPT", script);
+      break;
     }
-#endif
-  } else {
-    std::string e = "does not recognize <key> " + key;
-    status.SetError(e);
-    return false;
   }
 
-  return true;
+  makefile.RemoveDefinition(result_variable.data());
+
+  return data;
 }
 
-std::string ValueToString(size_t value)
+cm::optional<std::string> GetValue(cmExecutionStatus& status,
+                                   std::string const& key,
+                                   std::string const& variable)
 {
-  return std::to_string(value);
+  const auto prefix = "DISTRIB_"_s;
+  if (!cmHasPrefix(key, prefix)) {
+    return {};
+  }
+
+  static const std::map<std::string, std::string> s_os_release =
+    GetOSReleaseVariables(status);
+
+  auto& makefile = status.GetMakefile();
+
+  const std::string subkey =
+    key.substr(prefix.size(), key.size() - prefix.size());
+  if (subkey == "INFO"_s) {
+    std::string vars;
+    for (const auto& kv : s_os_release) {
+      auto cmake_var_name = cmStrCat(variable, '_', kv.first);
+      vars += DELIM[!vars.empty()] + cmake_var_name;
+      makefile.AddDefinition(cmake_var_name, kv.second);
+    }
+    return cm::optional<std::string>(std::move(vars));
+  }
+
+  // Query individual variable
+  const auto it = s_os_release.find(subkey);
+  if (it != s_os_release.cend()) {
+    return it->second;
+  }
+
+  // NOTE Empty string means requested variable not set
+  return std::string{};
 }
 
-std::string ValueToString(const char* value)
+#ifdef HAVE_VS_SETUP_HELPER
+cm::optional<std::string> GetValue(cmExecutionStatus& status,
+                                   std::string const& key)
 {
-  std::string safe_string = value ? value : "";
-  return safe_string;
+  auto* const gg = status.GetMakefile().GetGlobalGenerator();
+  for (auto vs : { 15, 16, 17 }) {
+    if (key == cmStrCat("VS_"_s, vs, "_DIR"_s)) {
+      std::string value;
+      // If generating for the VS nn IDE, use the same instance.
+
+      if (cmHasPrefix(gg->GetName(), cmStrCat("Visual Studio "_s, vs, ' '))) {
+        cmGlobalVisualStudioVersionedGenerator* vsNNgen =
+          static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
+        if (vsNNgen->GetVSInstance(value)) {
+          return value;
+        }
+      }
+
+      // Otherwise, find a VS nn instance ourselves.
+      cmVSSetupAPIHelper vsSetupAPIHelper(vs);
+      if (vsSetupAPIHelper.GetVSInstanceInfo(value)) {
+        cmSystemTools::ConvertToUnixSlashes(value);
+      }
+      return value;
+    }
+  }
+
+  if (key == "VS_MSBUILD_COMMAND"_s && gg->IsVisualStudioAtLeast10()) {
+    cmGlobalVisualStudio10Generator* vs10gen =
+      static_cast<cmGlobalVisualStudio10Generator*>(gg);
+    return vs10gen->FindMSBuildCommandEarly(&status.GetMakefile());
+  }
+
+  return {};
 }
+#endif
 
-std::string ValueToString(std::string const& value)
+cm::optional<std::string> GetValueChained()
 {
-  return value;
+  return {};
 }
+
+template <typename GetterFn, typename... Next>
+cm::optional<std::string> GetValueChained(GetterFn current, Next... chain)
+{
+  auto value = current();
+  if (value.has_value()) {
+    return value;
+  }
+  return GetValueChained(chain...);
+}
+// END Private functions
+} // anonymous namespace
+
+// cmCMakeHostSystemInformation
+bool cmCMakeHostSystemInformationCommand(std::vector<std::string> const& args,
+                                         cmExecutionStatus& status)
+{
+  std::size_t current_index = 0;
+
+  if (args.size() < (current_index + 2) || args[current_index] != "RESULT"_s) {
+    status.SetError("missing RESULT specification.");
+    return false;
+  }
+
+  auto const& variable = args[current_index + 1];
+  current_index += 2;
+
+  if (args.size() < (current_index + 2) || args[current_index] != "QUERY"_s) {
+    status.SetError("missing QUERY specification");
+    return false;
+  }
+
+  static cmsys::SystemInformation info;
+  static auto initialized = false;
+  if (!initialized) {
+    info.RunCPUCheck();
+    info.RunOSCheck();
+    info.RunMemoryCheck();
+    initialized = true;
+  }
+
+  std::string result_list;
+  for (auto i = current_index + 1; i < args.size(); ++i) {
+    result_list += DELIM[!result_list.empty()];
+
+    auto const& key = args[i];
+    // clang-format off
+    auto value =
+      GetValueChained(
+          [&]() { return GetValue(info, key); }
+        , [&]() { return GetValue(status, key, variable); }
+#ifdef HAVE_VS_SETUP_HELPER
+        , [&]() { return GetValue(status, key); }
+#endif
+        );
+    // clang-format on
+    if (!value) {
+      status.SetError("does not recognize <key> " + key);
+      return false;
+    }
+    result_list += value.value();
+  }
+
+  status.GetMakefile().AddDefinition(variable, result_list);
+
+  return true;
 }
index 9a5fa7b..bf94c2d 100644 (file)
 #include "cmCMakePath.h"
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmSubcommandTable.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 namespace {
 // Helper classes for argument parsing
@@ -150,7 +150,7 @@ public:
 bool getInputPath(const std::string& arg, cmExecutionStatus& status,
                   std::string& path)
 {
-  cmProp def = status.GetMakefile().GetDefinition(arg);
+  cmValue def = status.GetMakefile().GetDefinition(arg);
   if (!def) {
     status.SetError("undefined variable for input path.");
     return false;
index 1f99043..ebf639b 100644 (file)
@@ -9,6 +9,7 @@
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
+#include "cmValue.h"
 
 namespace {
 bool HandleSetMode(std::vector<std::string> const& args,
index ace7382..e460031 100644 (file)
@@ -140,7 +140,7 @@ const char* CCONV cmGetCurrentOutputDirectory(void* arg)
 const char* CCONV cmGetDefinition(void* arg, const char* def)
 {
   cmMakefile* mf = static_cast<cmMakefile*>(arg);
-  return cmToCStr(mf->GetDefinition(def));
+  return mf->GetDefinition(def).GetCStr();
 }
 
 int CCONV cmIsOn(void* arg, const char* name)
@@ -173,7 +173,7 @@ void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt,
       std::string(tgt) + " for directory " + std::string(d));
     return;
   }
-  t->InsertLinkDirectory(d, mf->GetBacktrace());
+  t->InsertLinkDirectory(BT<std::string>(d, mf->GetBacktrace()));
 }
 
 void CCONV cmAddExecutable(void* arg, const char* exename, int numSrcs,
@@ -592,12 +592,12 @@ const char* CCONV cmSourceFileGetProperty(void* arg, const char* prop)
 {
   cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
   if (cmSourceFile* rsf = sf->RealSourceFile) {
-    return cmToCStr(rsf->GetProperty(prop));
+    return rsf->GetProperty(prop).GetCStr();
   }
   if (!strcmp(prop, "LOCATION")) {
     return sf->FullPath.c_str();
   }
-  return cmToCStr(sf->Properties.GetPropertyValue(prop));
+  return sf->Properties.GetPropertyValue(prop).GetCStr();
 }
 
 int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop)
index 7c469c8..dfd2b6c 100644 (file)
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmProcessOutput.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 #include "cmVersionConfig.h"
 #include "cmXMLWriter.h"
@@ -1457,11 +1457,11 @@ void cmCTest::AddSiteProperties(cmXMLWriter& xml)
     return;
   }
   // This code should go when cdash is changed to use labels only
-  cmProp subproject = cm->GetState()->GetGlobalProperty("SubProject");
+  cmValue subproject = cm->GetState()->GetGlobalProperty("SubProject");
   if (subproject) {
     xml.StartElement("Subproject");
     xml.Attribute("name", *subproject);
-    cmProp labels =
+    cmValue labels =
       ch->GetCMake()->GetState()->GetGlobalProperty("SubProjectLabels");
     if (labels) {
       xml.StartElement("Labels");
@@ -1475,7 +1475,7 @@ void cmCTest::AddSiteProperties(cmXMLWriter& xml)
   }
 
   // This code should stay when cdash only does label based sub-projects
-  cmProp label = cm->GetState()->GetGlobalProperty("Label");
+  cmValue label = cm->GetState()->GetGlobalProperty("Label");
   if (label) {
     xml.StartElement("Labels");
     xml.Element("Label", *label);
@@ -2425,7 +2425,7 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName,
         case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum::
           Extra:
           this->Impl->ExtraVerbose = true;
-          // intentional fallthrough
+          CM_FALLTHROUGH;
         case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum::
           Verbose:
           this->Impl->Verbose = true;
@@ -3056,7 +3056,7 @@ int cmCTest::ReadCustomConfigurationFileTree(const std::string& dir,
 void cmCTest::PopulateCustomVector(cmMakefile* mf, const std::string& def,
                                    std::vector<std::string>& vec)
 {
-  cmProp dval = mf->GetDefinition(def);
+  cmValue dval = mf->GetDefinition(def);
   if (!dval) {
     return;
   }
@@ -3073,7 +3073,7 @@ void cmCTest::PopulateCustomVector(cmMakefile* mf, const std::string& def,
 void cmCTest::PopulateCustomInteger(cmMakefile* mf, const std::string& def,
                                     int& val)
 {
-  cmProp dval = mf->GetDefinition(def);
+  cmValue dval = mf->GetDefinition(def);
   if (!dval) {
     return;
   }
@@ -3407,7 +3407,7 @@ bool cmCTest::SetCTestConfigurationFromCMakeVariable(
   cmMakefile* mf, const char* dconfig, const std::string& cmake_var,
   bool suppress)
 {
-  cmProp ctvar = mf->GetDefinition(cmake_var);
+  cmValue ctvar = mf->GetDefinition(cmake_var);
   if (!ctvar) {
     return false;
   }
index 1a950df..b9d1f66 100644 (file)
@@ -118,13 +118,13 @@ bool cmCacheManager::LoadCache(const std::string& path, bool internal,
   }
   this->CacheMajorVersion = 0;
   this->CacheMinorVersion = 0;
-  if (cmProp cmajor =
+  if (cmValue cmajor =
         this->GetInitializedCacheValue("CMAKE_CACHE_MAJOR_VERSION")) {
     unsigned int v = 0;
     if (sscanf(cmajor->c_str(), "%u", &v) == 1) {
       this->CacheMajorVersion = v;
     }
-    if (cmProp cminor =
+    if (cmValue cminor =
           this->GetInitializedCacheValue("CMAKE_CACHE_MINOR_VERSION")) {
       if (sscanf(cminor->c_str(), "%u", &v) == 1) {
         this->CacheMinorVersion = v;
@@ -144,7 +144,7 @@ bool cmCacheManager::LoadCache(const std::string& path, bool internal,
   }
   // check to make sure the cache directory has not
   // been moved
-  cmProp oldDir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
+  cmValue oldDir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
   if (internal && oldDir) {
     std::string currentcwd = path;
     std::string oldcwd = *oldDir;
@@ -152,7 +152,7 @@ bool cmCacheManager::LoadCache(const std::string& path, bool internal,
     currentcwd += "/CMakeCache.txt";
     oldcwd += "/CMakeCache.txt";
     if (!cmSystemTools::SameFile(oldcwd, currentcwd)) {
-      cmProp dir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
+      cmValue dir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
       std::ostringstream message;
       message << "The current CMakeCache.txt directory " << currentcwd
               << " is different than the directory " << (dir ? *dir : "")
@@ -203,7 +203,7 @@ void cmCacheManager::WritePropertyEntries(std::ostream& os,
                                           cmMessenger* messenger) const
 {
   for (const char* p : cmCacheManager::PersistentProperties) {
-    if (cmProp value = e.GetProperty(p)) {
+    if (cmValue value = e.GetProperty(p)) {
       std::string helpstring =
         cmStrCat(p, " property for variable: ", entryKey);
       cmCacheManager::OutputHelpString(os, helpstring);
@@ -232,17 +232,17 @@ bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
   // before writing the cache, update the version numbers
   // to the
   this->AddCacheEntry("CMAKE_CACHE_MAJOR_VERSION",
-                      std::to_string(cmVersion::GetMajorVersion()).c_str(),
+                      std::to_string(cmVersion::GetMajorVersion()),
                       "Major version of cmake used to create the "
                       "current loaded cache",
                       cmStateEnums::INTERNAL);
   this->AddCacheEntry("CMAKE_CACHE_MINOR_VERSION",
-                      std::to_string(cmVersion::GetMinorVersion()).c_str(),
+                      std::to_string(cmVersion::GetMinorVersion()),
                       "Minor version of cmake used to create the "
                       "current loaded cache",
                       cmStateEnums::INTERNAL);
   this->AddCacheEntry("CMAKE_CACHE_PATCH_VERSION",
-                      std::to_string(cmVersion::GetPatchVersion()).c_str(),
+                      std::to_string(cmVersion::GetPatchVersion()),
                       "Patch version of cmake used to create the "
                       "current loaded cache",
                       cmStateEnums::INTERNAL);
@@ -256,7 +256,7 @@ bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
     currentcwd[0] = static_cast<char>(currentcwd[0] - 'A' + 'a');
   }
   cmSystemTools::ConvertToUnixSlashes(currentcwd);
-  this->AddCacheEntry("CMAKE_CACHEFILE_DIR", currentcwd.c_str(),
+  this->AddCacheEntry("CMAKE_CACHEFILE_DIR", currentcwd,
                       "This is the directory where this CMakeCache.txt"
                       " was created",
                       cmStateEnums::INTERNAL);
@@ -296,7 +296,7 @@ bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
       */
     } else if (t != cmStateEnums::INTERNAL) {
       // Format is key:type=value
-      if (cmProp help = ce.GetProperty("HELPSTRING")) {
+      if (cmValue help = ce.GetProperty("HELPSTRING")) {
         cmCacheManager::OutputHelpString(fout, *help);
       } else {
         cmCacheManager::OutputHelpString(fout, "Missing description");
@@ -326,7 +326,7 @@ bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
     this->WritePropertyEntries(fout, i.first, i.second, messenger);
     if (t == cmStateEnums::INTERNAL) {
       // Format is key:type=value
-      if (cmProp help = i.second.GetProperty("HELPSTRING")) {
+      if (cmValue help = i.second.GetProperty("HELPSTRING")) {
         cmCacheManager::OutputHelpString(fout, *help);
       }
       cmCacheManager::OutputKey(fout, i.first);
@@ -496,11 +496,11 @@ const cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry(
   return nullptr;
 }
 
-cmProp cmCacheManager::GetInitializedCacheValue(const std::string& key) const
+cmValue cmCacheManager::GetInitializedCacheValue(const std::string& key) const
 {
   if (const auto* entry = this->GetCacheEntry(key)) {
     if (entry->Initialized) {
-      return &entry->GetValue();
+      return cmValue(entry->GetValue());
     }
   }
   return nullptr;
@@ -521,7 +521,7 @@ void cmCacheManager::PrintCache(std::ostream& out) const
          "=================================================\n";
 }
 
-void cmCacheManager::AddCacheEntry(const std::string& key, const char* value,
+void cmCacheManager::AddCacheEntry(const std::string& key, cmValue value,
                                    const char* helpString,
                                    cmStateEnums::CacheEntryType type)
 {
@@ -550,10 +550,10 @@ void cmCacheManager::AddCacheEntry(const std::string& key, const char* value,
                   : "(This variable does not exist and should not be used)");
 }
 
-void cmCacheManager::CacheEntry::SetValue(const char* value)
+void cmCacheManager::CacheEntry::SetValue(cmValue value)
 {
   if (value) {
-    this->Value = value;
+    this->Value = *value;
     this->Initialized = true;
   } else {
     this->Value.clear();
@@ -565,13 +565,13 @@ std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const
   return this->Properties.GetKeys();
 }
 
-cmProp cmCacheManager::CacheEntry::GetProperty(const std::string& prop) const
+cmValue cmCacheManager::CacheEntry::GetProperty(const std::string& prop) const
 {
   if (prop == "TYPE") {
-    return &cmState::CacheEntryTypeToString(this->Type);
+    return cmValue(cmState::CacheEntryTypeToString(this->Type));
   }
   if (prop == "VALUE") {
-    return &this->Value;
+    return cmValue(this->Value);
   }
   return this->Properties.GetPropertyValue(prop);
 }
index 7a9a7dc..bc3fb51 100644 (file)
@@ -11,9 +11,9 @@
 #include <utility>
 #include <vector>
 
-#include "cmProperty.h"
 #include "cmPropertyMap.h"
 #include "cmStateTypes.h"
+#include "cmValue.h"
 
 class cmMessenger;
 
@@ -31,13 +31,13 @@ class cmCacheManager
 
   public:
     const std::string& GetValue() const { return this->Value; }
-    void SetValue(const char*);
+    void SetValue(cmValue);
 
     cmStateEnums::CacheEntryType GetType() const { return this->Type; }
     void SetType(cmStateEnums::CacheEntryType ty) { this->Type = ty; }
 
     std::vector<std::string> GetPropertyList() const;
-    cmProp GetProperty(const std::string& property) const;
+    cmValue GetProperty(const std::string& property) const;
     bool GetPropertyAsBool(const std::string& property) const;
     void SetProperty(const std::string& property, const char* value);
     void SetProperty(const std::string& property, bool value);
@@ -70,12 +70,12 @@ public:
   bool IsCacheLoaded() const { return this->CacheLoaded; }
 
   //! Get a value from the cache given a key
-  cmProp GetInitializedCacheValue(const std::string& key) const;
+  cmValue GetInitializedCacheValue(const std::string& key) const;
 
-  cmProp GetCacheEntryValue(const std::string& key) const
+  cmValue GetCacheEntryValue(const std::string& key) const
   {
     if (const auto* entry = this->GetCacheEntry(key)) {
-      return &entry->GetValue();
+      return cmValue(entry->GetValue());
     }
     return nullptr;
   }
@@ -83,7 +83,7 @@ public:
   void SetCacheEntryValue(std::string const& key, std::string const& value)
   {
     if (auto* entry = this->GetCacheEntry(key)) {
-      entry->SetValue(value.c_str());
+      entry->SetValue(cmValue(value));
     }
   }
 
@@ -104,8 +104,8 @@ public:
     return {};
   }
 
-  cmProp GetCacheEntryProperty(std::string const& key,
-                               std::string const& propName) const
+  cmValue GetCacheEntryProperty(std::string const& key,
+                                std::string const& propName) const
   {
     if (const auto* entry = this->GetCacheEntry(key)) {
       return entry->GetProperty(propName);
@@ -173,6 +173,18 @@ public:
 
   //! Add an entry into the cache
   void AddCacheEntry(const std::string& key, const char* value,
+                     const char* helpString, cmStateEnums::CacheEntryType type)
+  {
+    this->AddCacheEntry(key,
+                        value ? cmValue(std::string(value)) : cmValue(nullptr),
+                        helpString, type);
+  }
+  void AddCacheEntry(const std::string& key, const std::string& value,
+                     const char* helpString, cmStateEnums::CacheEntryType type)
+  {
+    this->AddCacheEntry(key, cmValue(value), helpString, type);
+  }
+  void AddCacheEntry(const std::string& key, cmValue value,
                      const char* helpString,
                      cmStateEnums::CacheEntryType type);
 
index 68c56d9..f5a5190 100644 (file)
@@ -44,7 +44,7 @@ public:
   cmMakefile* GetMakefile() { return this->Makefile; }
 
   void SetExecutionStatus(cmExecutionStatus* s);
-  cmExecutionStatus* GetExecutionStatus() { return this->Status; };
+  cmExecutionStatus* GetExecutionStatus() { return this->Status; }
 
   /**
    * This is called by the cmMakefile when the command is first
index deddba8..2ed04e5 100644 (file)
 #include "cmCommandArgumentLexer.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 int cmCommandArgument_yyparse(yyscan_t yyscanner);
 //
@@ -73,7 +73,8 @@ const char* cmCommandArgumentParserHelper::ExpandSpecialVariable(
     return "";
   }
   if (strcmp(key, "CACHE") == 0) {
-    if (cmProp c = this->Makefile->GetState()->GetInitializedCacheValue(var)) {
+    if (cmValue c =
+          this->Makefile->GetState()->GetInitializedCacheValue(var)) {
       if (this->EscapeQuotes) {
         return this->AddString(cmEscapeQuotes(*c));
       }
@@ -103,7 +104,7 @@ const char* cmCommandArgumentParserHelper::ExpandVariable(const char* var)
     }
     return this->AddString(line);
   }
-  cmProp value = this->Makefile->GetDefinition(var);
+  cmValue value = this->Makefile->GetDefinition(var);
   if (!value) {
     this->Makefile->MaybeWarnUninitialized(var, this->FileName);
     if (!this->RemoveEmpty) {
@@ -113,7 +114,7 @@ const char* cmCommandArgumentParserHelper::ExpandVariable(const char* var)
   if (this->EscapeQuotes && value) {
     return this->AddString(cmEscapeQuotes(*value));
   }
-  return this->AddString(cmToCStrSafe(value));
+  return this->AddString(value);
 }
 
 const char* cmCommandArgumentParserHelper::ExpandVariableForAt(const char* var)
index 7c2e20c..8d5ce7e 100644 (file)
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 
 cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt)
   : GeneratorTarget(gt)
@@ -39,10 +39,10 @@ std::vector<std::string> const& cmCommonTargetGenerator::GetConfigNames() const
   return this->ConfigNames;
 }
 
-const char* cmCommonTargetGenerator::GetFeature(const std::string& feature,
-                                                const std::string& config)
+cmValue cmCommonTargetGenerator::GetFeature(const std::string& feature,
+                                            const std::string& config)
 {
-  return this->GeneratorTarget->GetFeature(feature, config)->c_str();
+  return this->GeneratorTarget->GetFeature(feature, config);
 }
 
 void cmCommonTargetGenerator::AddModuleDefinitionFlag(
@@ -56,7 +56,7 @@ void cmCommonTargetGenerator::AddModuleDefinitionFlag(
   }
 
   // TODO: Create a per-language flag variable.
-  cmProp defFileFlag =
+  cmValue defFileFlag =
     this->Makefile->GetDefinition("CMAKE_LINK_DEF_FILE_FLAG");
   if (!defFileFlag) {
     return;
@@ -240,11 +240,16 @@ std::string cmCommonTargetGenerator::GetManifests(const std::string& config)
 
   std::vector<std::string> manifests;
   manifests.reserve(manifest_srcs.size());
+
+  std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
+  std::string const& manifestFlag =
+    this->Makefile->GetDefinition("CMAKE_" + lang + "_LINKER_MANIFEST_FLAG");
   for (cmSourceFile const* manifest_src : manifest_srcs) {
-    manifests.push_back(this->LocalCommonGenerator->ConvertToOutputFormat(
-      this->LocalCommonGenerator->MaybeRelativeToWorkDir(
-        manifest_src->GetFullPath()),
-      cmOutputConverter::SHELL));
+    manifests.push_back(manifestFlag +
+                        this->LocalCommonGenerator->ConvertToOutputFormat(
+                          this->LocalCommonGenerator->MaybeRelativeToWorkDir(
+                            manifest_src->GetFullPath()),
+                          cmOutputConverter::SHELL));
   }
 
   return cmJoin(manifests, " ");
@@ -254,7 +259,7 @@ std::string cmCommonTargetGenerator::GetAIXExports(std::string const&)
 {
   std::string aixExports;
   if (this->GeneratorTarget->Target->IsAIX()) {
-    if (cmProp exportAll =
+    if (cmValue exportAll =
           this->GeneratorTarget->GetProperty("AIX_EXPORT_ALL_SYMBOLS")) {
       if (cmIsOff(*exportAll)) {
         aixExports = "-n";
@@ -270,7 +275,7 @@ void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags,
 {
   // Lookup the flag to specify the version.
   std::string fvar = cmStrCat("CMAKE_", lang, "_OSX_", name, "_VERSION_FLAG");
-  cmProp flag = this->Makefile->GetDefinition(fvar);
+  cmValue flag = this->Makefile->GetDefinition(fvar);
 
   // Skip if no such flag.
   if (!flag) {
@@ -297,7 +302,7 @@ std::string cmCommonTargetGenerator::GetLinkerLauncher(
   const std::string& config)
 {
   std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
-  cmProp launcherProp =
+  cmValue launcherProp =
     this->GeneratorTarget->GetProperty(lang + "_LINKER_LAUNCHER");
   if (cmNonempty(launcherProp)) {
     // Convert ;-delimited list to single string
index a156a41..baa36c9 100644 (file)
@@ -8,6 +8,8 @@
 #include <string>
 #include <vector>
 
+#include "cmValue.h"
+
 class cmGeneratorTarget;
 class cmGlobalCommonGenerator;
 class cmLinkLineComputer;
@@ -28,8 +30,7 @@ public:
 
 protected:
   // Feature query methods.
-  const char* GetFeature(const std::string& feature,
-                         const std::string& config);
+  cmValue GetFeature(const std::string& feature, const std::string& config);
 
   // Helper to add flag for windows .def file.
   void AddModuleDefinitionFlag(cmLinkLineComputer* linkLineComputer,
@@ -40,6 +41,7 @@ protected:
   cmLocalCommonGenerator* LocalCommonGenerator;
   cmGlobalCommonGenerator* GlobalCommonGenerator;
   std::vector<std::string> ConfigNames;
+  bool UseLWYU = false;
 
   void AppendFortranFormatFlags(std::string& flags,
                                 cmSourceFile const& source);
index 0b27e34..370ddff 100644 (file)
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 /*
@@ -322,7 +322,7 @@ int cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item)
   } else {
     // Look for an old-style <item>_LIB_DEPENDS variable.
     std::string var = cmStrCat(entry.Item.Value, "_LIB_DEPENDS");
-    if (cmProp val = this->Makefile->GetDefinition(var)) {
+    if (cmValue val = this->Makefile->GetDefinition(var)) {
       // The item dependencies are known.  Follow them.
       BFSEntry qe = { index, val->c_str() };
       this->BFSQueue.push(qe);
@@ -489,7 +489,7 @@ void cmComputeLinkDepends::AddVarLinkEntries(int depender_index,
       // lower.
       if (!haveLLT) {
         std::string var = cmStrCat(d, "_LINK_TYPE");
-        if (cmProp val = this->Makefile->GetDefinition(var)) {
+        if (cmValue val = this->Makefile->GetDefinition(var)) {
           if (*val == "debug") {
             llt = DEBUG_LibraryType;
           } else if (*val == "optimized") {
@@ -607,7 +607,7 @@ cmLinkItem cmComputeLinkDepends::ResolveLinkItem(int depender_index,
       from = depender;
     }
   }
-  return from->ResolveLinkItem(name, cmListFileBacktrace());
+  return from->ResolveLinkItem(BT<std::string>(name));
 }
 
 void cmComputeLinkDepends::InferDependencies()
index d15da0c..831a81f 100644 (file)
 #include "cmOrderDirectories.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 //#define CM_COMPUTE_LINK_INFO_DEBUG
@@ -278,38 +278,36 @@ cmComputeLinkInformation::cmComputeLinkInformation(
   // On platforms without import libraries there may be a special flag
   // to use when creating a plugin (module) that obtains symbols from
   // the program that will load it.
-  this->LoaderFlag = nullptr;
   if (!this->Target->IsDLLPlatform() &&
       this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) {
     std::string loader_flag_var =
       cmStrCat("CMAKE_SHARED_MODULE_LOADER_", this->LinkLanguage, "_FLAG");
-    this->LoaderFlag =
-      cmToCStr(this->Makefile->GetDefinition(loader_flag_var));
+    this->LoaderFlag = this->Makefile->GetDefinition(loader_flag_var);
   }
 
   // Get options needed to link libraries.
-  if (cmProp flag = this->Makefile->GetDefinition(
+  if (cmValue flag = this->Makefile->GetDefinition(
         "CMAKE_" + this->LinkLanguage + "_LINK_LIBRARY_FLAG")) {
     this->LibLinkFlag = *flag;
   } else {
     this->LibLinkFlag =
       this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG");
   }
-  if (cmProp flag = this->Makefile->GetDefinition(
+  if (cmValue flag = this->Makefile->GetDefinition(
         "CMAKE_" + this->LinkLanguage + "_LINK_LIBRARY_FILE_FLAG")) {
     this->LibLinkFileFlag = *flag;
   } else {
     this->LibLinkFileFlag =
       this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FILE_FLAG");
   }
-  if (cmProp suffix = this->Makefile->GetDefinition(
+  if (cmValue suffix = this->Makefile->GetDefinition(
         "CMAKE_" + this->LinkLanguage + "_LINK_LIBRARY_SUFFIX")) {
     this->LibLinkSuffix = *suffix;
   } else {
     this->LibLinkSuffix =
       this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
   }
-  if (cmProp flag = this->Makefile->GetDefinition(
+  if (cmValue flag = this->Makefile->GetDefinition(
         "CMAKE_" + this->LinkLanguage + "_LINK_OBJECT_FILE_FLAG")) {
     this->ObjLinkFileFlag = *flag;
   } else {
@@ -528,7 +526,7 @@ bool cmComputeLinkInformation::Compute()
 
   // Restore the target link type so the correct system runtime
   // libraries are found.
-  cmProp lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC");
+  cmValue lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC");
   if (cmIsOn(lss)) {
     this->SetCurrentLinkType(LinkStatic);
   } else {
@@ -607,7 +605,7 @@ void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang)
   if (runtimeLibrary.empty()) {
     return;
   }
-  if (cmProp runtimeLinkOptions = this->Makefile->GetDefinition(
+  if (cmValue runtimeLinkOptions = this->Makefile->GetDefinition(
         "CMAKE_" + lang + "_RUNTIME_LIBRARY_LINK_OPTIONS_" + runtimeLibrary)) {
     std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions);
     for (std::string const& i : libsVec) {
@@ -623,7 +621,7 @@ void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang)
   // Add libraries for this language that are not implied by the
   // linker language.
   std::string libVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_LIBRARIES");
-  if (cmProp libs = this->Makefile->GetDefinition(libVar)) {
+  if (cmValue libs = this->Makefile->GetDefinition(libVar)) {
     std::vector<std::string> libsVec = cmExpandedList(*libs);
     for (std::string const& i : libsVec) {
       if (!cm::contains(this->ImplicitLinkLibs, i)) {
@@ -635,7 +633,7 @@ void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang)
   // Add linker search paths for this language that are not
   // implied by the linker language.
   std::string dirVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_DIRECTORIES");
-  if (cmProp dirs = this->Makefile->GetDefinition(dirVar)) {
+  if (cmValue dirs = this->Makefile->GetDefinition(dirVar)) {
     std::vector<std::string> dirsVec = cmExpandedList(*dirs);
     this->OrderLinkerSearchPath->AddLanguageDirectories(dirsVec);
   }
@@ -660,8 +658,7 @@ void cmComputeLinkInformation::AddItem(BT<std::string> const& item,
       // This link item is an executable that may provide symbols
       // used by this target.  A special flag is needed on this
       // platform.  Add it now.
-      std::string linkItem;
-      linkItem = this->LoaderFlag;
+      std::string linkItem = this->LoaderFlag;
       cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
         ? cmStateEnums::ImportLibraryArtifact
         : cmStateEnums::RuntimeBinaryArtifact;
@@ -839,8 +836,8 @@ void cmComputeLinkInformation::ComputeLinkTypeInfo()
   this->LinkTypeEnabled = false;
 
   // Lookup link type selection flags.
-  cmProp static_link_type_flag = nullptr;
-  cmProp shared_link_type_flag = nullptr;
+  cmValue static_link_type_flag = nullptr;
+  cmValue shared_link_type_flag = nullptr;
   const char* target_type_str = nullptr;
   switch (this->Target->GetType()) {
     case cmStateEnums::EXECUTABLE:
@@ -878,7 +875,7 @@ void cmComputeLinkInformation::ComputeLinkTypeInfo()
   }
 
   // Lookup the starting link type from the target (linked statically?).
-  cmProp lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC");
+  cmValue lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC");
   this->StartLinkType = cmIsOn(lss) ? LinkStatic : LinkShared;
   this->CurrentLinkType = this->StartLinkType;
 }
@@ -900,13 +897,14 @@ void cmComputeLinkInformation::ComputeItemParserInfo()
                          LinkShared);
   this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX"),
                          LinkUnknown);
-  if (cmProp linkSuffixes = mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) {
+  if (cmValue linkSuffixes =
+        mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) {
     std::vector<std::string> linkSuffixVec = cmExpandedList(*linkSuffixes);
     for (std::string const& i : linkSuffixVec) {
       this->AddLinkExtension(i, LinkUnknown);
     }
   }
-  if (cmProp sharedSuffixes =
+  if (cmValue sharedSuffixes =
         mf->GetDefinition("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")) {
     std::vector<std::string> sharedSuffixVec = cmExpandedList(*sharedSuffixes);
     for (std::string const& i : sharedSuffixVec) {
@@ -1187,6 +1185,7 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item)
           this->CMP0060WarnItems.insert(item);
         }
       }
+      CM_FALLTHROUGH;
     case cmPolicies::OLD:
       break;
     case cmPolicies::REQUIRED_ALWAYS:
@@ -1456,8 +1455,10 @@ void cmComputeLinkInformation::HandleBadFullItem(std::string const& item,
                                           this->Target->GetBacktrace());
       }
     }
-    case cmPolicies::OLD:
+      CM_FALLTHROUGH;
+    case cmPolicies::OLD: // NOLINT(bugprone-branch-clone)
       // OLD behavior does not warn.
+      break;
     case cmPolicies::NEW:
       // NEW behavior will not get here.
       break;
@@ -1496,6 +1497,7 @@ bool cmComputeLinkInformation::FinishLinkerSearchDirectories()
         this->CMakeInstance->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
                                           this->Target->GetBacktrace());
       }
+      CM_FALLTHROUGH;
     case cmPolicies::OLD:
       // OLD behavior is to add the paths containing libraries with
       // known full paths as link directories.
@@ -1592,7 +1594,7 @@ void cmComputeLinkInformation::LoadImplicitLinkInfo()
 
   // Append library architecture to all implicit platform directories
   // and add them to the set
-  if (cmProp libraryArch =
+  if (cmValue libraryArch =
         this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) {
     for (std::string const& i : implicitDirVec) {
       this->ImplicitLinkDirs.insert(i + "/" + *libraryArch);
@@ -1785,13 +1787,13 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
   }
   if (use_build_rpath || use_link_rpath) {
     std::string rootPath;
-    if (cmProp sysrootLink =
+    if (cmValue sysrootLink =
           this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
       rootPath = *sysrootLink;
     } else {
       rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
     }
-    cmProp stagePath = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
+    cmValue stagePath = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
     std::string const& installPrefix =
       this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
     cmSystemTools::ConvertToUnixSlashes(rootPath);
@@ -1859,7 +1861,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
         "CMAKE_" + li + "_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH";
       if (this->Makefile->IsOn(useVar)) {
         std::string dirVar = "CMAKE_" + li + "_IMPLICIT_LINK_DIRECTORIES";
-        if (cmProp dirs = this->Makefile->GetDefinition(dirVar)) {
+        if (cmValue dirs = this->Makefile->GetDefinition(dirVar)) {
           cmCLI_ExpandListUnique(*dirs, runtimeDirs, emitted);
         }
       }
index 7fe30b3..90a699e 100644 (file)
@@ -14,6 +14,7 @@
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmListFileCache.h"
+#include "cmValue.h"
 
 class cmGeneratorTarget;
 class cmGlobalGenerator;
@@ -137,7 +138,7 @@ private:
     SharedDepModeLink    // List file on link line
   };
 
-  const char* LoaderFlag;
+  cmValue LoaderFlag;
   std::string LibLinkFlag;
   std::string LibLinkFileFlag;
   std::string ObjLinkFileFlag;
index 76712f4..ef89c8b 100644 (file)
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmSourceFileLocationKind.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
-#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTargetDepend.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 /*
@@ -323,7 +322,7 @@ void cmComputeTargetDepends::AddObjectDepends(int depender_index,
   }
   cmGeneratorTarget const* depender = this->Targets[depender_index];
   cmLinkItem const& objItem =
-    depender->ResolveLinkItem(objLib, cmListFileBacktrace());
+    depender->ResolveLinkItem(BT<std::string>(objLib));
   if (emitted.insert(objItem).second) {
     if (depender->GetType() != cmStateEnums::EXECUTABLE &&
         depender->GetType() != cmStateEnums::STATIC_LIBRARY &&
@@ -360,6 +359,7 @@ void cmComputeTargetDepends::AddTargetDepend(int depender_index,
       case cmPolicies::WARN:
         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0046) << "\n";
         issueMessage = true;
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         break;
       case cmPolicies::NEW:
@@ -367,6 +367,7 @@ void cmComputeTargetDepends::AddTargetDepend(int depender_index,
       case cmPolicies::REQUIRED_ALWAYS:
         issueMessage = true;
         messageType = MessageType::FATAL_ERROR;
+        break;
     }
     if (issueMessage) {
       cmake* cm = this->GlobalGenerator->GetCMakeInstance();
@@ -469,7 +470,7 @@ void cmComputeTargetDepends::ComputeIntermediateGraph()
         gt->GetType() != cmStateEnums::OBJECT_LIBRARY) {
       intermediateEdges = initialEdges;
     } else {
-      if (cmProp optimizeDependencies =
+      if (cmValue optimizeDependencies =
             gt->GetProperty("OPTIMIZE_DEPENDENCIES")) {
         if (cmIsOn(optimizeDependencies)) {
           this->OptimizeLinkDependencies(gt, intermediateEdges, initialEdges);
index f99592c..8e479c5 100644 (file)
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmConditionEvaluator.h"
 
+#include <array>
 #include <cstdio>
 #include <cstdlib>
 #include <functional>
+#include <iterator>
+#include <list>
 #include <sstream>
 #include <utility>
 
+#include <cm/string_view>
 #include <cmext/algorithm>
 
 #include "cmsys/RegularExpression.hxx"
 
+#include "cmExpandedCommandArgument.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
-class cmTest;
-
-static std::string const keyAND = "AND";
-static std::string const keyCOMMAND = "COMMAND";
-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";
-static std::string const keyParenL = "(";
-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";
+namespace {
+auto const keyAND = "AND"_s;
+auto const keyCOMMAND = "COMMAND"_s;
+auto const keyDEFINED = "DEFINED"_s;
+auto const keyEQUAL = "EQUAL"_s;
+auto const keyEXISTS = "EXISTS"_s;
+auto const keyGREATER = "GREATER"_s;
+auto const keyGREATER_EQUAL = "GREATER_EQUAL"_s;
+auto const keyIN_LIST = "IN_LIST"_s;
+auto const keyIS_ABSOLUTE = "IS_ABSOLUTE"_s;
+auto const keyIS_DIRECTORY = "IS_DIRECTORY"_s;
+auto const keyIS_NEWER_THAN = "IS_NEWER_THAN"_s;
+auto const keyIS_SYMLINK = "IS_SYMLINK"_s;
+auto const keyLESS = "LESS"_s;
+auto const keyLESS_EQUAL = "LESS_EQUAL"_s;
+auto const keyMATCHES = "MATCHES"_s;
+auto const keyNOT = "NOT"_s;
+auto const keyOR = "OR"_s;
+auto const keyParenL = "("_s;
+auto const keyParenR = ")"_s;
+auto const keyPOLICY = "POLICY"_s;
+auto const keySTREQUAL = "STREQUAL"_s;
+auto const keySTRGREATER = "STRGREATER"_s;
+auto const keySTRGREATER_EQUAL = "STRGREATER_EQUAL"_s;
+auto const keySTRLESS = "STRLESS"_s;
+auto const keySTRLESS_EQUAL = "STRLESS_EQUAL"_s;
+auto const keyTARGET = "TARGET"_s;
+auto const keyTEST = "TEST"_s;
+auto const keyVERSION_EQUAL = "VERSION_EQUAL"_s;
+auto const keyVERSION_GREATER = "VERSION_GREATER"_s;
+auto const keyVERSION_GREATER_EQUAL = "VERSION_GREATER_EQUAL"_s;
+auto const keyVERSION_LESS = "VERSION_LESS"_s;
+auto const keyVERSION_LESS_EQUAL = "VERSION_LESS_EQUAL"_s;
+
+cmSystemTools::CompareOp const MATCH2CMPOP[5] = {
+  cmSystemTools::OP_LESS, cmSystemTools::OP_LESS_EQUAL,
+  cmSystemTools::OP_GREATER, cmSystemTools::OP_GREATER_EQUAL,
+  cmSystemTools::OP_EQUAL
+};
+
+// Run-Time to Compile-Time template selector
+template <template <typename> class Comp, template <typename> class... Ops>
+struct cmRt2CtSelector
+{
+  template <typename T>
+  static bool eval(int r, T lhs, T rhs)
+  {
+    switch (r) {
+      case 0:
+        return false;
+      case 1:
+        return Comp<T>()(lhs, rhs);
+      default:
+        return cmRt2CtSelector<Ops...>::eval(r - 1, lhs, rhs);
+    }
+  }
+};
+
+template <template <typename> class Comp>
+struct cmRt2CtSelector<Comp>
+{
+  template <typename T>
+  static bool eval(int r, T lhs, T rhs)
+  {
+    return r == 1 && Comp<T>()(lhs, rhs);
+  }
+};
+
+std::string bool2string(bool const value)
+{
+  return std::string(std::size_t(1), static_cast<char>('0' + int(value)));
+}
+
+bool looksLikeSpecialVariable(const std::string& var,
+                              cm::static_string_view prefix,
+                              const std::size_t varNameLen)
+{
+  // NOTE Expecting a variable name at least 1 char length:
+  // <prefix> + `{` + <varname> + `}`
+  return ((prefix.size() + 3) <= varNameLen) &&
+    cmHasPrefix(var, cmStrCat(prefix, '{')) && var[varNameLen - 1] == '}';
+}
+} // anonymous namespace
+
+#if defined(__SUNPRO_CC)
+#  define CM_INHERIT_CTOR(Class, Base, Tpl)                                   \
+    template <typename... Args>                                               \
+    Class(Args&&... args)                                                     \
+      : Base Tpl(std::forward<Args>(args)...)                                 \
+    {                                                                         \
+    }
+#else
+#  define CM_INHERIT_CTOR(Class, Base, Tpl) using Base Tpl ::Base
+#endif
+
+// BEGIN cmConditionEvaluator::cmArgumentList
+class cmConditionEvaluator::cmArgumentList
+  : public std::list<cmExpandedCommandArgument>
+{
+  using base_t = std::list<cmExpandedCommandArgument>;
+
+public:
+  CM_INHERIT_CTOR(cmArgumentList, list, <cmExpandedCommandArgument>);
+
+  class CurrentAndNextIter
+  {
+    friend class cmConditionEvaluator::cmArgumentList;
+
+  public:
+    base_t::iterator current;
+    base_t::iterator next;
+
+    CurrentAndNextIter advance(base_t& args)
+    {
+      this->current = std::next(this->current);
+      this->next =
+        std::next(this->current, difference_type(this->current != args.end()));
+      return *this;
+    }
+
+  private:
+    CurrentAndNextIter(base_t& args)
+      : current(args.begin())
+      , next(std::next(this->current,
+                       difference_type(this->current != args.end())))
+    {
+    }
+  };
+
+  class CurrentAndTwoMoreIter
+  {
+    friend class cmConditionEvaluator::cmArgumentList;
+
+  public:
+    base_t::iterator current;
+    base_t::iterator next;
+    base_t::iterator nextnext;
+
+    CurrentAndTwoMoreIter advance(base_t& args)
+    {
+      this->current = std::next(this->current);
+      this->next =
+        std::next(this->current, difference_type(this->current != args.end()));
+      this->nextnext =
+        std::next(this->next, difference_type(this->next != args.end()));
+      return *this;
+    }
+
+  private:
+    CurrentAndTwoMoreIter(base_t& args)
+      : current(args.begin())
+      , next(std::next(this->current,
+                       difference_type(this->current != args.end())))
+      , nextnext(
+          std::next(this->next, difference_type(this->next != args.end())))
+    {
+    }
+  };
+
+  CurrentAndNextIter make2ArgsIterator() { return *this; }
+  CurrentAndTwoMoreIter make3ArgsIterator() { return *this; }
+
+  template <typename Iter>
+  void ReduceOneArg(const bool value, Iter args)
+  {
+    *args.current = cmExpandedCommandArgument(bool2string(value), true);
+    this->erase(args.next);
+  }
+
+  void ReduceTwoArgs(const bool value, CurrentAndTwoMoreIter args)
+  {
+    *args.current = cmExpandedCommandArgument(bool2string(value), true);
+    this->erase(args.nextnext);
+    this->erase(args.next);
+  }
+};
+
+// END cmConditionEvaluator::cmArgumentList
 
 cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile,
                                            cmListFileBacktrace bt)
@@ -99,25 +248,29 @@ bool cmConditionEvaluator::IsTrue(
   // now loop through the arguments and see if we can reduce any of them
   // we do this multiple times. Once for each level of precedence
   // parens
-  if (!this->HandleLevel0(newArgs, errorString, status)) {
-    return false;
-  }
-  // predicates
-  if (!this->HandleLevel1(newArgs, errorString, status)) {
-    return false;
-  }
-  // binary ops
-  if (!this->HandleLevel2(newArgs, errorString, status)) {
-    return false;
-  }
+  using handlerFn_t = bool (cmConditionEvaluator::*)(
+    cmArgumentList&, std::string&, MessageType&);
+  const std::array<handlerFn_t, 5> handlers = { {
+    &cmConditionEvaluator::HandleLevel0, // parenthesis
+    &cmConditionEvaluator::HandleLevel1, // predicates
+    &cmConditionEvaluator::HandleLevel2, // binary ops
+    &cmConditionEvaluator::HandleLevel3, // NOT
+    &cmConditionEvaluator::HandleLevel4  // AND OR
+  } };
+  for (auto fn : handlers) {
+    // Call the reducer 'till there is anything to reduce...
+    // (i.e., if after an iteration the size becomes smaller)
+    auto levelResult = true;
+    for (auto beginSize = newArgs.size();
+         (levelResult = (this->*fn)(newArgs, errorString, status)) &&
+         newArgs.size() < beginSize;
+         beginSize = newArgs.size()) {
+    }
 
-  // NOT
-  if (!this->HandleLevel3(newArgs, errorString, status)) {
-    return false;
-  }
-  // AND OR
-  if (!this->HandleLevel4(newArgs, errorString, status)) {
-    return false;
+    if (!levelResult) {
+      // NOTE `errorString` supposed to be set already
+      return false;
+    }
   }
 
   // now at the end there should only be one argument left
@@ -132,7 +285,7 @@ bool cmConditionEvaluator::IsTrue(
 }
 
 //=========================================================================
-cmProp cmConditionEvaluator::GetDefinitionIfUnquoted(
+cmValue cmConditionEvaluator::GetDefinitionIfUnquoted(
   cmExpandedCommandArgument const& argument) const
 {
   if ((this->Policy54Status != cmPolicies::WARN &&
@@ -141,17 +294,19 @@ cmProp cmConditionEvaluator::GetDefinitionIfUnquoted(
     return nullptr;
   }
 
-  cmProp def = this->Makefile.GetDefinition(argument.GetValue());
+  cmValue def = this->Makefile.GetDefinition(argument.GetValue());
 
   if (def && argument.WasQuoted() &&
       this->Policy54Status == cmPolicies::WARN) {
     if (!this->Makefile.HasCMP0054AlreadyBeenReported(this->Backtrace.Top())) {
       std::ostringstream e;
-      e << (cmPolicies::GetPolicyWarning(cmPolicies::CMP0054)) << "\n";
-      e << "Quoted variables like \"" << argument.GetValue()
-        << "\" will no longer be dereferenced "
-           "when the policy is set to NEW.  "
+      // clang-format off
+      e << (cmPolicies::GetPolicyWarning(cmPolicies::CMP0054))
+        << "\n"
+           "Quoted variables like \"" << argument.GetValue() << "\" "
+           "will no longer be dereferenced when the policy is set to NEW.  "
            "Since the policy is not set the OLD behavior will be used.";
+      // clang-format on
 
       this->Makefile.GetCMakeInstance()->IssueMessage(
         MessageType::AUTHOR_WARNING, e.str(), this->Backtrace);
@@ -162,21 +317,22 @@ cmProp cmConditionEvaluator::GetDefinitionIfUnquoted(
 }
 
 //=========================================================================
-cmProp cmConditionEvaluator::GetVariableOrString(
+cmValue cmConditionEvaluator::GetVariableOrString(
   const cmExpandedCommandArgument& argument) const
 {
-  cmProp def = this->GetDefinitionIfUnquoted(argument);
+  cmValue def = this->GetDefinitionIfUnquoted(argument);
 
   if (!def) {
-    def = &argument.GetValue();
+    def = cmValue(argument.GetValue());
   }
 
   return def;
 }
 
 //=========================================================================
-bool cmConditionEvaluator::IsKeyword(std::string const& keyword,
-                                     cmExpandedCommandArgument& argument) const
+bool cmConditionEvaluator::IsKeyword(
+  cm::static_string_view keyword,
+  const cmExpandedCommandArgument& argument) const
 {
   if ((this->Policy54Status != cmPolicies::WARN &&
        this->Policy54Status != cmPolicies::OLD) &&
@@ -184,17 +340,20 @@ bool cmConditionEvaluator::IsKeyword(std::string const& keyword,
     return false;
   }
 
-  bool isKeyword = argument.GetValue() == keyword;
+  const auto isKeyword = argument.GetValue() == keyword;
 
   if (isKeyword && argument.WasQuoted() &&
       this->Policy54Status == cmPolicies::WARN) {
     if (!this->Makefile.HasCMP0054AlreadyBeenReported(this->Backtrace.Top())) {
       std::ostringstream e;
-      e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0054) << "\n";
-      e << "Quoted keywords like \"" << argument.GetValue()
-        << "\" will no longer be interpreted as keywords "
+      // clang-format off
+      e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0054)
+        << "\n"
+           "Quoted keywords like \"" << argument.GetValue() << "\" "
+           "will no longer be interpreted as keywords "
            "when the policy is set to NEW.  "
            "Since the policy is not set the OLD behavior will be used.";
+      // clang-format on
 
       this->Makefile.GetCMakeInstance()->IssueMessage(
         MessageType::AUTHOR_WARNING, e.str(), this->Backtrace);
@@ -208,15 +367,7 @@ bool cmConditionEvaluator::IsKeyword(std::string const& keyword,
 bool cmConditionEvaluator::GetBooleanValue(
   cmExpandedCommandArgument& arg) const
 {
-  // Check basic constants.
-  if (arg == "0") {
-    return false;
-  }
-  if (arg == "1") {
-    return true;
-  }
-
-  // Check named constants.
+  // Check basic and named constants.
   if (cmIsOn(arg.GetValue())) {
     return true;
   }
@@ -227,7 +378,7 @@ bool cmConditionEvaluator::GetBooleanValue(
   // Check for numbers.
   if (!arg.empty()) {
     char* end;
-    double d = strtod(arg.GetValue().c_str(), &end);
+    const double d = std::strtod(arg.GetValue().c_str(), &end);
     if (*end == '\0') {
       // The whole string is a number.  Use C conversion to bool.
       return static_cast<bool>(d);
@@ -235,14 +386,14 @@ bool cmConditionEvaluator::GetBooleanValue(
   }
 
   // Check definition.
-  cmProp def = this->GetDefinitionIfUnquoted(arg);
+  cmValue def = this->GetDefinitionIfUnquoted(arg);
   return !cmIsOff(def);
 }
 
 //=========================================================================
 // Boolean value behavior from CMake 2.6.4 and below.
 bool cmConditionEvaluator::GetBooleanValueOld(
-  cmExpandedCommandArgument const& arg, bool one) const
+  cmExpandedCommandArgument const& arg, bool const one) const
 {
   if (one) {
     // Old IsTrue behavior for single argument.
@@ -252,13 +403,13 @@ bool cmConditionEvaluator::GetBooleanValueOld(
     if (arg == "1") {
       return true;
     }
-    cmProp def = this->GetDefinitionIfUnquoted(arg);
+    cmValue def = this->GetDefinitionIfUnquoted(arg);
     return !cmIsOff(def);
   }
   // Old GetVariableOrNumber behavior.
-  cmProp def = this->GetDefinitionIfUnquoted(arg);
-  if (!def && atoi(arg.GetValue().c_str())) {
-    def = &arg.GetValue();
+  cmValue def = this->GetDefinitionIfUnquoted(arg);
+  if (!def && std::atoi(arg.GetValue().c_str())) {
+    def = cmValue(arg.GetValue());
   }
   return !cmIsOff(def);
 }
@@ -267,7 +418,7 @@ bool cmConditionEvaluator::GetBooleanValueOld(
 // returns the resulting boolean value
 bool cmConditionEvaluator::GetBooleanValueWithAutoDereference(
   cmExpandedCommandArgument& newArg, std::string& errorString,
-  MessageType& status, bool oneArg) const
+  MessageType& status, bool const oneArg) const
 {
   // Use the policy if it is set.
   if (this->Policy12Status == cmPolicies::NEW) {
@@ -278,8 +429,8 @@ bool cmConditionEvaluator::GetBooleanValueWithAutoDereference(
   }
 
   // Check policy only if old and new results differ.
-  bool newResult = this->GetBooleanValue(newArg);
-  bool oldResult = this->GetBooleanValueOld(newArg, oneArg);
+  const auto newResult = this->GetBooleanValue(newArg);
+  const auto oldResult = this->GetBooleanValueOld(newArg, oneArg);
   if (newResult != oldResult) {
     switch (this->Policy12Status) {
       case cmPolicies::WARN:
@@ -296,6 +447,7 @@ bool cmConditionEvaluator::GetBooleanValueWithAutoDereference(
           "\" appears in a conditional statement.  " +
           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0012);
         status = MessageType::FATAL_ERROR;
+        break;
       }
       case cmPolicies::NEW:
         break;
@@ -304,56 +456,31 @@ bool cmConditionEvaluator::GetBooleanValueWithAutoDereference(
   return newResult;
 }
 
-//=========================================================================
-void cmConditionEvaluator::IncrementArguments(
-  cmArgumentList& newArgs, cmArgumentList::iterator& argP1,
-  cmArgumentList::iterator& argP2) const
+template <int N>
+inline int cmConditionEvaluator::matchKeysImpl(
+  const cmExpandedCommandArgument&)
 {
-  if (argP1 != newArgs.end()) {
-    argP1++;
-    argP2 = argP1;
-    if (argP1 != newArgs.end()) {
-      argP2++;
-    }
-  }
+  // Zero means "not found"
+  return 0;
 }
 
-//=========================================================================
-// helper function to reduce code duplication
-void cmConditionEvaluator::HandlePredicate(
-  bool value, int& reducible, cmArgumentList::iterator& arg,
-  cmArgumentList& newArgs, cmArgumentList::iterator& argP1,
-  cmArgumentList::iterator& argP2) const
+template <int N, typename T, typename... Keys>
+inline int cmConditionEvaluator::matchKeysImpl(
+  const cmExpandedCommandArgument& arg, T current, Keys... key)
 {
-  if (value) {
-    *arg = cmExpandedCommandArgument("1", true);
-  } else {
-    *arg = cmExpandedCommandArgument("0", true);
+  if (this->IsKeyword(current, arg)) {
+    // Stop searching as soon as smth has found
+    return N;
   }
-  newArgs.erase(argP1);
-  argP1 = arg;
-  this->IncrementArguments(newArgs, argP1, argP2);
-  reducible = 1;
+  return matchKeysImpl<N + 1>(arg, key...);
 }
 
-//=========================================================================
-// helper function to reduce code duplication
-void cmConditionEvaluator::HandleBinaryOp(bool value, int& reducible,
-                                          cmArgumentList::iterator& arg,
-                                          cmArgumentList& newArgs,
-                                          cmArgumentList::iterator& argP1,
-                                          cmArgumentList::iterator& argP2)
+template <typename... Keys>
+inline int cmConditionEvaluator::matchKeys(
+  const cmExpandedCommandArgument& arg, Keys... key)
 {
-  if (value) {
-    *arg = cmExpandedCommandArgument("1", true);
-  } else {
-    *arg = cmExpandedCommandArgument("0", true);
-  }
-  newArgs.erase(argP2);
-  newArgs.erase(argP1);
-  argP1 = arg;
-  this->IncrementArguments(newArgs, argP1, argP2);
-  reducible = 1;
+  // Get index of the matched key (1-based)
+  return matchKeysImpl<1>(arg, key...);
 }
 
 //=========================================================================
@@ -362,55 +489,35 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList& newArgs,
                                         std::string& errorString,
                                         MessageType& status)
 {
-  int reducible;
-  do {
-    reducible = 0;
-    auto arg = newArgs.begin();
-    while (arg != newArgs.end()) {
-      if (this->IsKeyword(keyParenL, *arg)) {
-        // search for the closing paren for this opening one
-        cmArgumentList::iterator argClose;
-        argClose = arg;
-        argClose++;
-        unsigned int depth = 1;
-        while (argClose != newArgs.end() && depth) {
-          if (this->IsKeyword(keyParenL, *argClose)) {
-            depth++;
-          }
-          if (this->IsKeyword(keyParenR, *argClose)) {
-            depth--;
-          }
-          argClose++;
-        }
-        if (depth) {
-          errorString = "mismatched parenthesis in condition";
-          status = MessageType::FATAL_ERROR;
-          return false;
-        }
-        // store the reduced args in this vector
-        std::vector<cmExpandedCommandArgument> newArgs2;
-
-        // copy to the list structure
-        auto argP1 = arg;
-        argP1++;
-        cm::append(newArgs2, argP1, argClose);
-        newArgs2.pop_back();
-        // now recursively invoke IsTrue to handle the values inside the
-        // parenthetical expression
-        bool value = this->IsTrue(newArgs2, errorString, status);
-        if (value) {
-          *arg = cmExpandedCommandArgument("1", true);
-        } else {
-          *arg = cmExpandedCommandArgument("0", true);
-        }
-        argP1 = arg;
-        argP1++;
-        // remove the now evaluated parenthetical expression
-        newArgs.erase(argP1, argClose);
+  for (auto arg = newArgs.begin(); arg != newArgs.end(); ++arg) {
+    if (this->IsKeyword(keyParenL, *arg)) {
+      // search for the closing paren for this opening one
+      auto depth = 1;
+      auto argClose = std::next(arg);
+      for (; argClose != newArgs.end() && depth; ++argClose) {
+        depth += int(this->IsKeyword(keyParenL, *argClose)) -
+          int(this->IsKeyword(keyParenR, *argClose));
       }
-      ++arg;
+      if (depth) {
+        errorString = "mismatched parenthesis in condition";
+        status = MessageType::FATAL_ERROR;
+        return false;
+      }
+
+      // store the reduced args in this vector
+      auto argOpen = std::next(arg);
+      const std::vector<cmExpandedCommandArgument> subExpr(
+        argOpen, std::prev(argClose));
+
+      // now recursively invoke IsTrue to handle the values inside the
+      // parenthetical expression
+      const auto value = this->IsTrue(subExpr, errorString, status);
+      *arg = cmExpandedCommandArgument(bool2string(value), true);
+      argOpen = std::next(arg);
+      // remove the now evaluated parenthetical expression
+      newArgs.erase(argOpen, argClose);
     }
-  } while (reducible);
+  }
   return true;
 }
 
@@ -419,96 +526,104 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList& newArgs,
 bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&,
                                         MessageType&)
 {
-  int reducible;
-  do {
-    reducible = 0;
-    auto arg = newArgs.begin();
-    cmArgumentList::iterator argP1;
-    cmArgumentList::iterator argP2;
-    while (arg != newArgs.end()) {
-      argP1 = arg;
-      this->IncrementArguments(newArgs, argP1, argP2);
-      // does a file exist
-      if (this->IsKeyword(keyEXISTS, *arg) && argP1 != newArgs.end()) {
-        this->HandlePredicate(cmSystemTools::FileExists(argP1->GetValue()),
-                              reducible, arg, newArgs, argP1, argP2);
-      }
-      // does a directory with this name exist
-      if (this->IsKeyword(keyIS_DIRECTORY, *arg) && argP1 != newArgs.end()) {
-        this->HandlePredicate(
-          cmSystemTools::FileIsDirectory(argP1->GetValue()), reducible, arg,
-          newArgs, argP1, argP2);
-      }
-      // does a symlink with this name exist
-      if (this->IsKeyword(keyIS_SYMLINK, *arg) && argP1 != newArgs.end()) {
-        this->HandlePredicate(cmSystemTools::FileIsSymlink(argP1->GetValue()),
-                              reducible, arg, newArgs, argP1, argP2);
-      }
-      // is the given path an absolute path ?
-      if (this->IsKeyword(keyIS_ABSOLUTE, *arg) && argP1 != newArgs.end()) {
-        this->HandlePredicate(cmSystemTools::FileIsFullPath(argP1->GetValue()),
-                              reducible, arg, newArgs, argP1, argP2);
-      }
-      // does a command exist
-      if (this->IsKeyword(keyCOMMAND, *arg) && argP1 != newArgs.end()) {
-        cmState::Command command =
-          this->Makefile.GetState()->GetCommand(argP1->GetValue());
-        this->HandlePredicate(command != nullptr, reducible, arg, newArgs,
-                              argP1, argP2);
-      }
-      // does a policy exist
-      if (this->IsKeyword(keyPOLICY, *arg) && argP1 != newArgs.end()) {
-        cmPolicies::PolicyID pid;
-        this->HandlePredicate(
-          cmPolicies::GetPolicyID(argP1->GetValue().c_str(), pid), reducible,
-          arg, newArgs, argP1, argP2);
-      }
-      // does a target exist
-      if (this->IsKeyword(keyTARGET, *arg) && argP1 != newArgs.end()) {
-        this->HandlePredicate(
-          this->Makefile.FindTargetToUse(argP1->GetValue()) != nullptr,
-          reducible, arg, newArgs, argP1, argP2);
-      }
-      // does a test exist
-      if (this->Policy64Status != cmPolicies::OLD &&
-          this->Policy64Status != cmPolicies::WARN) {
-        if (this->IsKeyword(keyTEST, *arg) && argP1 != newArgs.end()) {
-          const cmTest* haveTest = this->Makefile.GetTest(argP1->GetValue());
-          this->HandlePredicate(haveTest != nullptr, reducible, arg, newArgs,
-                                argP1, argP2);
-        }
-      } else if (this->Policy64Status == cmPolicies::WARN &&
-                 this->IsKeyword(keyTEST, *arg)) {
+  const auto policy64IsOld = this->Policy64Status == cmPolicies::OLD ||
+    this->Policy64Status == cmPolicies::WARN;
+
+  for (auto args = newArgs.make2ArgsIterator(); args.current != newArgs.end();
+       args.advance(newArgs)) {
+
+    auto policyCheck = [&, this](const cmPolicies::PolicyID id,
+                                 const cmPolicies::PolicyStatus status,
+                                 const cm::static_string_view kw) {
+      if (status == cmPolicies::WARN && this->IsKeyword(kw, *args.current)) {
         std::ostringstream e;
-        e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0064) << "\n";
-        e << "TEST will be interpreted as an operator "
+        e << cmPolicies::GetPolicyWarning(id) << "\n"
+          << kw
+          << " will be interpreted as an operator "
              "when the policy is set to NEW.  "
              "Since the policy is not set the OLD behavior will be used.";
 
         this->Makefile.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
       }
-      // is a variable defined
-      if (this->IsKeyword(keyDEFINED, *arg) && argP1 != newArgs.end()) {
-        size_t argP1len = argP1->GetValue().size();
-        bool bdef = false;
-        if (argP1len > 4 && cmHasLiteralPrefix(argP1->GetValue(), "ENV{") &&
-            argP1->GetValue().operator[](argP1len - 1) == '}') {
-          std::string env = argP1->GetValue().substr(4, argP1len - 5);
-          bdef = cmSystemTools::HasEnv(env);
-        } else if (argP1len > 6 &&
-                   cmHasLiteralPrefix(argP1->GetValue(), "CACHE{") &&
-                   argP1->GetValue().operator[](argP1len - 1) == '}') {
-          std::string cache = argP1->GetValue().substr(6, argP1len - 7);
-          bdef =
-            this->Makefile.GetState()->GetCacheEntryValue(cache) != nullptr;
-        } else {
-          bdef = this->Makefile.IsDefinitionSet(argP1->GetValue());
-        }
-        this->HandlePredicate(bdef, reducible, arg, newArgs, argP1, argP2);
+    };
+
+    // NOTE Checking policies for warnings are not require an access to the
+    // next arg. Check them first!
+    policyCheck(cmPolicies::CMP0064, this->Policy64Status, keyTEST);
+
+    // NOTE Fail fast: All the predicates below require the next arg to be
+    // valid
+    if (args.next == newArgs.end()) {
+      continue;
+    }
+
+    // does a file exist
+    if (this->IsKeyword(keyEXISTS, *args.current)) {
+      newArgs.ReduceOneArg(cmSystemTools::FileExists(args.next->GetValue()),
+                           args);
+    }
+    // does a directory with this name exist
+    else if (this->IsKeyword(keyIS_DIRECTORY, *args.current)) {
+      newArgs.ReduceOneArg(
+        cmSystemTools::FileIsDirectory(args.next->GetValue()), args);
+    }
+    // does a symlink with this name exist
+    else if (this->IsKeyword(keyIS_SYMLINK, *args.current)) {
+      newArgs.ReduceOneArg(cmSystemTools::FileIsSymlink(args.next->GetValue()),
+                           args);
+    }
+    // is the given path an absolute path ?
+    else if (this->IsKeyword(keyIS_ABSOLUTE, *args.current)) {
+      newArgs.ReduceOneArg(
+        cmSystemTools::FileIsFullPath(args.next->GetValue()), args);
+    }
+    // does a command exist
+    else if (this->IsKeyword(keyCOMMAND, *args.current)) {
+      newArgs.ReduceOneArg(
+        bool(this->Makefile.GetState()->GetCommand(args.next->GetValue())),
+        args);
+    }
+    // does a policy exist
+    else if (this->IsKeyword(keyPOLICY, *args.current)) {
+      cmPolicies::PolicyID pid;
+      newArgs.ReduceOneArg(
+        cmPolicies::GetPolicyID(args.next->GetValue().c_str(), pid), args);
+    }
+    // does a target exist
+    else if (this->IsKeyword(keyTARGET, *args.current)) {
+      newArgs.ReduceOneArg(
+        bool(this->Makefile.FindTargetToUse(args.next->GetValue())), args);
+    }
+    // is a variable defined
+    else if (this->IsKeyword(keyDEFINED, *args.current)) {
+      const auto& var = args.next->GetValue();
+      const auto varNameLen = var.size();
+
+      auto result = false;
+      if (looksLikeSpecialVariable(var, "ENV"_s, varNameLen)) {
+        const auto env = args.next->GetValue().substr(4, varNameLen - 5);
+        result = cmSystemTools::HasEnv(env);
+      }
+
+      else if (looksLikeSpecialVariable(var, "CACHE"_s, varNameLen)) {
+        const auto cache = args.next->GetValue().substr(6, varNameLen - 7);
+        result = bool(this->Makefile.GetState()->GetCacheEntryValue(cache));
       }
-      ++arg;
+
+      else {
+        result = this->Makefile.IsDefinitionSet(args.next->GetValue());
+      }
+      newArgs.ReduceOneArg(result, args);
+    }
+    // does a test exist
+    else if (this->IsKeyword(keyTEST, *args.current)) {
+      if (policy64IsOld) {
+        continue;
+      }
+      newArgs.ReduceOneArg(bool(this->Makefile.GetTest(args.next->GetValue())),
+                           args);
     }
-  } while (reducible);
+  }
   return true;
 }
 
@@ -518,178 +633,142 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs,
                                         std::string& errorString,
                                         MessageType& status)
 {
-  int reducible;
-  std::string def_buf;
-  cmProp def;
-  cmProp def2;
-  do {
-    reducible = 0;
-    auto arg = newArgs.begin();
-    cmArgumentList::iterator argP1;
-    cmArgumentList::iterator argP2;
-    while (arg != newArgs.end()) {
-      argP1 = arg;
-      this->IncrementArguments(newArgs, argP1, argP2);
-      if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
-          this->IsKeyword(keyMATCHES, *argP1)) {
-        def = this->GetDefinitionIfUnquoted(*arg);
-        if (!def) {
-          def = &arg->GetValue();
-        } else if (cmHasLiteralPrefix(arg->GetValue(), "CMAKE_MATCH_")) {
-          // The string to match is owned by our match result variables.
-          // Move it to our own buffer before clearing them.
-          def_buf = *def;
-          def = &def_buf;
-        }
-        const std::string& rex = argP2->GetValue();
-        this->Makefile.ClearMatches();
-        cmsys::RegularExpression regEntry;
-        if (!regEntry.compile(rex)) {
-          std::ostringstream error;
-          error << "Regular expression \"" << rex << "\" cannot compile";
-          errorString = error.str();
-          status = MessageType::FATAL_ERROR;
-          return false;
-        }
-        if (regEntry.find(*def)) {
-          this->Makefile.StoreMatches(regEntry);
-          *arg = cmExpandedCommandArgument("1", true);
-        } else {
-          *arg = cmExpandedCommandArgument("0", true);
-        }
-        newArgs.erase(argP2);
-        newArgs.erase(argP1);
-        argP1 = arg;
-        this->IncrementArguments(newArgs, argP1, argP2);
-        reducible = 1;
-      }
+  for (auto args = newArgs.make3ArgsIterator(); args.current != newArgs.end();
+       args.advance(newArgs)) {
 
-      if (argP1 != newArgs.end() && this->IsKeyword(keyMATCHES, *arg)) {
-        *arg = cmExpandedCommandArgument("0", true);
-        newArgs.erase(argP1);
-        argP1 = arg;
-        this->IncrementArguments(newArgs, argP1, argP2);
-        reducible = 1;
-      }
+    int matchNo;
 
-      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);
-        double lhs;
-        double rhs;
-        bool result;
-        if (sscanf(def->c_str(), "%lg", &lhs) != 1 ||
-            sscanf(def2->c_str(), "%lg", &rhs) != 1) {
-          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);
-        }
-        this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
-      }
+    // NOTE Handle special case `if(... BLAH_BLAH MATCHES)`
+    // (i.e., w/o regex to match which is possibly result of
+    // variable expansion to an empty string)
+    if (args.next != newArgs.end() &&
+        this->IsKeyword(keyMATCHES, *args.current)) {
+      newArgs.ReduceOneArg(false, args);
+    }
+
+    // NOTE Fail fast: All the binary ops below require 2 arguments.
+    else if (args.next == newArgs.end() || args.nextnext == newArgs.end()) {
+      continue;
+    }
 
-      if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
-          (this->IsKeyword(keySTRLESS, *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 = (*def).compare(*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);
-        }
-        this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
+    else if (this->IsKeyword(keyMATCHES, *args.next)) {
+      cmValue def = this->GetDefinitionIfUnquoted(*args.current);
+
+      std::string def_buf;
+      if (!def) {
+        def = cmValue(args.current->GetValue());
+      } else if (cmHasLiteralPrefix(args.current->GetValue(),
+                                    "CMAKE_MATCH_")) {
+        // The string to match is owned by our match result variables.
+        // Move it to our own buffer before clearing them.
+        def_buf = *def;
+        def = cmValue(def_buf);
       }
 
-      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;
-        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->c_str(), def2->c_str());
-        this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
+      this->Makefile.ClearMatches();
+
+      const auto& rex = args.nextnext->GetValue();
+      cmsys::RegularExpression regEntry;
+      if (!regEntry.compile(rex)) {
+        std::ostringstream error;
+        error << "Regular expression \"" << rex << "\" cannot compile";
+        errorString = error.str();
+        status = MessageType::FATAL_ERROR;
+        return false;
       }
 
-      // is file A newer than file B
-      if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
-          this->IsKeyword(keyIS_NEWER_THAN, *argP1)) {
-        int fileIsNewer = 0;
-        cmsys::Status ftcStatus = cmSystemTools::FileTimeCompare(
-          arg->GetValue(), (argP2)->GetValue(), &fileIsNewer);
-        this->HandleBinaryOp(
-          (!ftcStatus || fileIsNewer == 1 || fileIsNewer == 0), reducible, arg,
-          newArgs, argP1, argP2);
+      const auto match = regEntry.find(*def);
+      if (match) {
+        this->Makefile.StoreMatches(regEntry);
       }
+      newArgs.ReduceTwoArgs(match, args);
+    }
+
+    else if ((matchNo =
+                this->matchKeys(*args.next, keyLESS, keyLESS_EQUAL, keyGREATER,
+                                keyGREATER_EQUAL, keyEQUAL))) {
+
+      cmValue ldef = this->GetVariableOrString(*args.current);
+      cmValue rdef = this->GetVariableOrString(*args.nextnext);
+
+      double lhs;
+      double rhs;
+      auto parseDoubles = [&]() {
+        return std::sscanf(ldef->c_str(), "%lg", &lhs) == 1 &&
+          std::sscanf(rdef->c_str(), "%lg", &rhs) == 1;
+      };
+      // clang-format off
+      const auto result = parseDoubles() &&
+        cmRt2CtSelector<
+            std::less, std::less_equal,
+            std::greater, std::greater_equal,
+            std::equal_to
+          >::eval(matchNo, lhs, rhs);
+      // clang-format on
+      newArgs.ReduceTwoArgs(result, args);
+    }
+
+    else if ((matchNo = this->matchKeys(*args.next, keySTRLESS,
+                                        keySTRLESS_EQUAL, keySTRGREATER,
+                                        keySTRGREATER_EQUAL, keySTREQUAL))) {
+
+      const cmValue lhs = this->GetVariableOrString(*args.current);
+      const cmValue rhs = this->GetVariableOrString(*args.nextnext);
+      const auto val = (*lhs).compare(*rhs);
+      // clang-format off
+      const auto result = cmRt2CtSelector<
+            std::less, std::less_equal,
+            std::greater, std::greater_equal,
+            std::equal_to
+          >::eval(matchNo, val, 0);
+      // clang-format on
+      newArgs.ReduceTwoArgs(result, args);
+    }
+
+    else if ((matchNo =
+                this->matchKeys(*args.next, keyVERSION_LESS,
+                                keyVERSION_LESS_EQUAL, keyVERSION_GREATER,
+                                keyVERSION_GREATER_EQUAL, keyVERSION_EQUAL))) {
+      const auto op = MATCH2CMPOP[matchNo - 1];
+      const std::string& lhs = this->GetVariableOrString(*args.current);
+      const std::string& rhs = this->GetVariableOrString(*args.nextnext);
+      const auto result = cmSystemTools::VersionCompare(op, lhs, rhs);
+      newArgs.ReduceTwoArgs(result, args);
+    }
+
+    // is file A newer than file B
+    else if (this->IsKeyword(keyIS_NEWER_THAN, *args.next)) {
+      auto fileIsNewer = 0;
+      cmsys::Status ftcStatus = cmSystemTools::FileTimeCompare(
+        args.current->GetValue(), args.nextnext->GetValue(), &fileIsNewer);
+      newArgs.ReduceTwoArgs(
+        (!ftcStatus || fileIsNewer == 1 || fileIsNewer == 0), args);
+    }
+
+    else if (this->IsKeyword(keyIN_LIST, *args.next)) {
 
-      if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
-          this->IsKeyword(keyIN_LIST, *argP1)) {
-        if (this->Policy57Status != cmPolicies::OLD &&
-            this->Policy57Status != cmPolicies::WARN) {
-          bool result = false;
-
-          def = this->GetVariableOrString(*arg);
-          def2 = this->Makefile.GetDefinition(argP2->GetValue());
-
-          if (def2) {
-            std::vector<std::string> list = cmExpandedList(*def2, true);
-            result = cm::contains(list, *def);
-          }
-
-          this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
-        } else if (this->Policy57Status == cmPolicies::WARN) {
-          std::ostringstream e;
-          e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0057) << "\n";
-          e << "IN_LIST will be interpreted as an operator "
-               "when the policy is set to NEW.  "
-               "Since the policy is not set the OLD behavior will be used.";
-
-          this->Makefile.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
-        }
+      if (this->Policy57Status != cmPolicies::OLD &&
+          this->Policy57Status != cmPolicies::WARN) {
+
+        cmValue lhs = this->GetVariableOrString(*args.current);
+        cmValue rhs = this->Makefile.GetDefinition(args.nextnext->GetValue());
+
+        newArgs.ReduceTwoArgs(
+          rhs && cm::contains(cmExpandedList(*rhs, true), *lhs), args);
       }
 
-      ++arg;
+      else if (this->Policy57Status == cmPolicies::WARN) {
+        std::ostringstream e;
+        e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0057)
+          << "\n"
+             "IN_LIST will be interpreted as an operator "
+             "when the policy is set to NEW.  "
+             "Since the policy is not set the OLD behavior will be used.";
+
+        this->Makefile.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+      }
     }
-  } while (reducible);
+  }
   return true;
 }
 
@@ -699,23 +778,14 @@ bool cmConditionEvaluator::HandleLevel3(cmArgumentList& newArgs,
                                         std::string& errorString,
                                         MessageType& status)
 {
-  int reducible;
-  do {
-    reducible = 0;
-    auto arg = newArgs.begin();
-    cmArgumentList::iterator argP1;
-    cmArgumentList::iterator argP2;
-    while (arg != newArgs.end()) {
-      argP1 = arg;
-      this->IncrementArguments(newArgs, argP1, argP2);
-      if (argP1 != newArgs.end() && this->IsKeyword(keyNOT, *arg)) {
-        bool rhs = this->GetBooleanValueWithAutoDereference(
-          *argP1, errorString, status);
-        this->HandlePredicate(!rhs, reducible, arg, newArgs, argP1, argP2);
-      }
-      ++arg;
+  for (auto args = newArgs.make2ArgsIterator(); args.next != newArgs.end();
+       args.advance(newArgs)) {
+    if (this->IsKeyword(keyNOT, *args.current)) {
+      const auto rhs = this->GetBooleanValueWithAutoDereference(
+        *args.next, errorString, status);
+      newArgs.ReduceOneArg(!rhs, args);
     }
-  } while (reducible);
+  }
   return true;
 }
 
@@ -725,38 +795,24 @@ bool cmConditionEvaluator::HandleLevel4(cmArgumentList& newArgs,
                                         std::string& errorString,
                                         MessageType& status)
 {
-  int reducible;
-  bool lhs;
-  bool rhs;
-  do {
-    reducible = 0;
-    auto arg = newArgs.begin();
-    cmArgumentList::iterator argP1;
-    cmArgumentList::iterator argP2;
-    while (arg != newArgs.end()) {
-      argP1 = arg;
-      this->IncrementArguments(newArgs, argP1, argP2);
-      if (argP1 != newArgs.end() && this->IsKeyword(keyAND, *argP1) &&
-          argP2 != newArgs.end()) {
-        lhs =
-          this->GetBooleanValueWithAutoDereference(*arg, errorString, status);
-        rhs = this->GetBooleanValueWithAutoDereference(*argP2, errorString,
-                                                       status);
-        this->HandleBinaryOp((lhs && rhs), reducible, arg, newArgs, argP1,
-                             argP2);
-      }
-
-      if (argP1 != newArgs.end() && this->IsKeyword(keyOR, *argP1) &&
-          argP2 != newArgs.end()) {
-        lhs =
-          this->GetBooleanValueWithAutoDereference(*arg, errorString, status);
-        rhs = this->GetBooleanValueWithAutoDereference(*argP2, errorString,
-                                                       status);
-        this->HandleBinaryOp((lhs || rhs), reducible, arg, newArgs, argP1,
-                             argP2);
-      }
-      ++arg;
+  for (auto args = newArgs.make3ArgsIterator(); args.nextnext != newArgs.end();
+       args.advance(newArgs)) {
+
+    int matchNo;
+
+    if ((matchNo = this->matchKeys(*args.next, keyAND, keyOR))) {
+      const auto lhs = this->GetBooleanValueWithAutoDereference(
+        *args.current, errorString, status);
+      const auto rhs = this->GetBooleanValueWithAutoDereference(
+        *args.nextnext, errorString, status);
+      // clang-format off
+      const auto result =
+        cmRt2CtSelector<
+            std::logical_and, std::logical_or
+          >::eval(matchNo, lhs, rhs);
+      // clang-format on
+      newArgs.ReduceTwoArgs(result, args);
     }
-  } while (reducible);
+  }
   return true;
 }
index cf00ede..37b7825 100644 (file)
@@ -4,23 +4,22 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
-#include <list>
 #include <string>
 #include <vector>
 
-#include "cmExpandedCommandArgument.h"
+#include <cmext/string_view>
+
 #include "cmListFileCache.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
+#include "cmValue.h"
 
+class cmExpandedCommandArgument;
 class cmMakefile;
 
 class cmConditionEvaluator
 {
 public:
-  using cmArgumentList = std::list<cmExpandedCommandArgument>;
-
   cmConditionEvaluator(cmMakefile& makefile, cmListFileBacktrace bt);
 
   // this is a shared function for both If and Else to determine if the
@@ -30,14 +29,16 @@ public:
               std::string& errorString, MessageType& status);
 
 private:
+  class cmArgumentList;
+
   // Filter the given variable definition based on policy CMP0054.
-  cmProp GetDefinitionIfUnquoted(
+  cmValue GetDefinitionIfUnquoted(
     const cmExpandedCommandArgument& argument) const;
 
-  cmProp GetVariableOrString(const cmExpandedCommandArgument& argument) const;
+  cmValue GetVariableOrString(const cmExpandedCommandArgument& argument) const;
 
-  bool IsKeyword(std::string const& keyword,
-                 cmExpandedCommandArgument& argument) const;
+  bool IsKeyword(cm::static_string_view keyword,
+                 const cmExpandedCommandArgument& argument) const;
 
   bool GetBooleanValue(cmExpandedCommandArgument& arg) const;
 
@@ -49,19 +50,14 @@ private:
                                           MessageType& status,
                                           bool oneArg = false) const;
 
-  void IncrementArguments(cmArgumentList& newArgs,
-                          cmArgumentList::iterator& argP1,
-                          cmArgumentList::iterator& argP2) const;
+  template <int N>
+  int matchKeysImpl(const cmExpandedCommandArgument&);
 
-  void HandlePredicate(bool value, int& reducible,
-                       cmArgumentList::iterator& arg, cmArgumentList& newArgs,
-                       cmArgumentList::iterator& argP1,
-                       cmArgumentList::iterator& argP2) const;
+  template <int N, typename T, typename... Keys>
+  int matchKeysImpl(const cmExpandedCommandArgument&, T, Keys...);
 
-  void HandleBinaryOp(bool value, int& reducible,
-                      cmArgumentList::iterator& arg, cmArgumentList& newArgs,
-                      cmArgumentList::iterator& argP1,
-                      cmArgumentList::iterator& argP2);
+  template <typename... Keys>
+  int matchKeys(const cmExpandedCommandArgument&, Keys...);
 
   bool HandleLevel0(cmArgumentList& newArgs, std::string& errorString,
                     MessageType& status);
index aeca6b4..6a419f6 100644 (file)
@@ -16,7 +16,6 @@
 
 #cmakedefine HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE
 #cmakedefine HAVE_UNSETENV
-#cmakedefine CMake_USE_ELF_PARSER
 #cmakedefine CMake_USE_MACH_PARSER
 #cmakedefine CMake_USE_XCOFF_PARSER
 #define CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@
index bf18143..971c86e 100644 (file)
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 #include "cmake.h"
 
@@ -246,7 +246,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
   this->SrcFileSignature = true;
 
   cmStateEnums::TargetType targetType = cmStateEnums::EXECUTABLE;
-  cmProp tt = this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_TARGET_TYPE");
+  cmValue tt = this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_TARGET_TYPE");
   if (!isTryRun && cmNonempty(tt)) {
     if (*tt == cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) {
       targetType = cmStateEnums::EXECUTABLE;
@@ -540,7 +540,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
       return -1;
     }
 
-    cmProp def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH");
+    cmValue def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH");
     fprintf(fout, "cmake_minimum_required(VERSION %u.%u.%u.%u)\n",
             cmVersion::GetMajorVersion(), cmVersion::GetMinorVersion(),
             cmVersion::GetPatchVersion(), cmVersion::GetTweakVersion());
@@ -549,7 +549,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
     }
 
     /* Set MSVC runtime library policy to match our selection.  */
-    if (cmProp msvcRuntimeLibraryDefault =
+    if (cmValue msvcRuntimeLibraryDefault =
           this->Makefile->GetDefinition(kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)) {
       fprintf(fout, "cmake_policy(SET CMP0091 %s)\n",
               !msvcRuntimeLibraryDefault->empty() ? "NEW" : "OLD");
@@ -564,7 +564,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
     }
 
     /* Set ARMClang cpu/arch policy to match outer project.  */
-    if (cmProp cmp0123 =
+    if (cmValue cmp0123 =
           this->Makefile->GetDefinition(kCMAKE_ARMClang_CMP0123)) {
       fprintf(fout, "cmake_policy(SET CMP0123 %s)\n",
               *cmp0123 == "NEW"_s ? "NEW" : "OLD");
@@ -582,11 +582,11 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
       projectLangs += " " + li;
       std::string rulesOverrideBase = "CMAKE_USER_MAKE_RULES_OVERRIDE";
       std::string rulesOverrideLang = cmStrCat(rulesOverrideBase, "_", li);
-      if (cmProp rulesOverridePath =
+      if (cmValue rulesOverridePath =
             this->Makefile->GetDefinition(rulesOverrideLang)) {
         fprintf(fout, "set(%s \"%s\")\n", rulesOverrideLang.c_str(),
                 rulesOverridePath->c_str());
-      } else if (cmProp rulesOverridePath2 =
+      } else if (cmValue rulesOverridePath2 =
                    this->Makefile->GetDefinition(rulesOverrideBase)) {
         fprintf(fout, "set(%s \"%s\")\n", rulesOverrideBase.c_str(),
                 rulesOverridePath2->c_str());
@@ -604,9 +604,9 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
     fprintf(fout, "set(CMAKE_VERBOSE_MAKEFILE 1)\n");
     for (std::string const& li : testLangs) {
       std::string langFlags = "CMAKE_" + li + "_FLAGS";
-      cmProp flags = this->Makefile->GetDefinition(langFlags);
+      cmValue flags = this->Makefile->GetDefinition(langFlags);
       fprintf(fout, "set(CMAKE_%s_FLAGS %s)\n", li.c_str(),
-              cmOutputConverter::EscapeForCMake(cmToCStrSafe(flags)).c_str());
+              cmOutputConverter::EscapeForCMake(*flags).c_str());
       fprintf(fout,
               "set(CMAKE_%s_FLAGS \"${CMAKE_%s_FLAGS}"
               " ${COMPILE_DEFINITIONS}\")\n",
@@ -626,6 +626,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
           /* clang-format on */
           this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
         }
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         // OLD behavior is to do nothing.
         break;
@@ -643,10 +644,9 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
         for (std::string const& li : testLangs) {
           std::string const langFlagsCfg =
             cmStrCat("CMAKE_", li, "_FLAGS_", cfg);
-          cmProp flagsCfg = this->Makefile->GetDefinition(langFlagsCfg);
-          fprintf(
-            fout, "set(%s %s)\n", langFlagsCfg.c_str(),
-            cmOutputConverter::EscapeForCMake(cmToCStrSafe(flagsCfg)).c_str());
+          cmValue flagsCfg = this->Makefile->GetDefinition(langFlagsCfg);
+          fprintf(fout, "set(%s %s)\n", langFlagsCfg.c_str(),
+                  cmOutputConverter::EscapeForCMake(*flagsCfg).c_str());
         }
       } break;
     }
@@ -664,6 +664,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
           /* clang-format on */
           this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
         }
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         // OLD behavior is to do nothing.
         break;
@@ -676,11 +677,10 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
       case cmPolicies::NEW:
         // NEW behavior is to pass linker flags.
         {
-          cmProp exeLinkFlags =
+          cmValue exeLinkFlags =
             this->Makefile->GetDefinition("CMAKE_EXE_LINKER_FLAGS");
           fprintf(fout, "set(CMAKE_EXE_LINKER_FLAGS %s)\n",
-                  cmOutputConverter::EscapeForCMake(cmToCStrSafe(exeLinkFlags))
-                    .c_str());
+                  cmOutputConverter::EscapeForCMake(*exeLinkFlags).c_str());
         }
         break;
     }
@@ -762,7 +762,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
       vars.insert(kCMAKE_WARN_DEPRECATED);
       vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s);
 
-      if (cmProp varListStr = this->Makefile->GetDefinition(
+      if (cmValue varListStr = this->Makefile->GetDefinition(
             kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) {
         std::vector<std::string> varList = cmExpandedList(*varListStr);
         vars.insert(varList.begin(), varList.end());
@@ -801,7 +801,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
          cmLocalGenerator doesn't allow building for "the other"
          architecture only via CMAKE_OSX_ARCHITECTURES.
          */
-      if (cmProp tcArchs = this->Makefile->GetDefinition(
+      if (cmValue tcArchs = this->Makefile->GetDefinition(
             kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES)) {
         vars.erase(kCMAKE_OSX_ARCHITECTURES);
         std::string flag = "-DCMAKE_OSX_ARCHITECTURES=" + *tcArchs;
@@ -809,7 +809,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
       }
 
       for (std::string const& var : vars) {
-        if (cmProp val = this->Makefile->GetDefinition(var)) {
+        if (cmValue val = this->Makefile->GetDefinition(var)) {
           std::string flag = "-D" + var + "=" + *val;
           cmakeFlags.push_back(std::move(flag));
         }
@@ -880,6 +880,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
           this->Makefile->IssueMessage(
             MessageType::FATAL_ERROR,
             cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0067));
+          break;
         case cmPolicies::NEW:
           // NEW behavior is to honor the language standard variables.
           // We already initialized honorStandard to true.
@@ -954,7 +955,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
   if (this->Makefile->GetState()->UseGhsMultiIDE()) {
     // Forward the GHS variables to the inner project cache.
     for (std::string const& var : ghs_platform_vars) {
-      if (cmProp val = this->Makefile->GetDefinition(var)) {
+      if (cmValue val = this->Makefile->GetDefinition(var)) {
         std::string flag = "-D" + var + "=" + "'" + *val + "'";
         cmakeFlags.push_back(std::move(flag));
       }
@@ -1096,7 +1097,7 @@ void cmCoreTryCompile::FindOutputFile(const std::string& targetName,
   std::vector<std::string> searchDirs;
   searchDirs.emplace_back();
 
-  cmProp config =
+  cmValue config =
     this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
   // if a config was specified try that first
   if (cmNonempty(config)) {
index 233790e..28ee24d 100644 (file)
@@ -5,9 +5,17 @@
 #if !defined(CMAKE_USE_SYSTEM_CURL) && !defined(_WIN32) &&                    \
   !defined(__APPLE__) && !defined(CURL_CA_BUNDLE) && !defined(CURL_CA_PATH)
 #  define CMAKE_FIND_CAFILE
-#  include "cmSystemTools.h"
 #endif
 #include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+#if defined(_WIN32)
+#  include <vector>
+
+#  include <windows.h>
+
+#  include "cmsys/Encoding.hxx"
+#endif
 
 // curl versions before 7.21.5 did not provide this error code
 #if defined(LIBCURL_VERSION_NUM) && LIBCURL_VERSION_NUM < 0x071505
     }                                                                         \
   } while (false)
 
-std::string cmCurlSetCAInfo(::CURL* curl, const char* cafile)
+std::string cmCurlSetCAInfo(::CURL* curl, const std::string& cafile)
 {
   std::string e;
-  if (cafile && *cafile) {
-    ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_CAINFO, cafile);
+  if (!cafile.empty()) {
+    ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_CAINFO, cafile.c_str());
     check_curl_result(res, "Unable to set TLS/SSL Verify CAINFO: ");
   }
 #ifdef CMAKE_FIND_CAFILE
@@ -95,3 +103,35 @@ std::string cmCurlSetNETRCOption(::CURL* curl, const std::string& netrc_level,
   }
   return e;
 }
+
+std::string cmCurlFixFileURL(std::string url)
+{
+  if (!cmHasLiteralPrefix(url, "file://")) {
+    return url;
+  }
+
+  // libcurl 7.77 and below accidentally allowed spaces in URLs in some cases.
+  // One such case was file:// URLs, which CMake has long accepted as a result.
+  // Explicitly encode spaces for a URL.
+  cmSystemTools::ReplaceString(url, " ", "%20");
+
+#if defined(_WIN32)
+  // libcurl doesn't support file:// urls for unicode filenames on Windows.
+  // Convert string from UTF-8 to ACP if this is a file:// URL.
+  std::wstring wurl = cmsys::Encoding::ToWide(url);
+  if (!wurl.empty()) {
+    int mblen =
+      WideCharToMultiByte(CP_ACP, 0, wurl.c_str(), -1, NULL, 0, NULL, NULL);
+    if (mblen > 0) {
+      std::vector<char> chars(mblen);
+      mblen = WideCharToMultiByte(CP_ACP, 0, wurl.c_str(), -1, &chars[0],
+                                  mblen, NULL, NULL);
+      if (mblen > 0) {
+        url = &chars[0];
+      }
+    }
+  }
+#endif
+
+  return url;
+}
index fb716f8..b5134f4 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <cm3p/curl/curl.h>
 
-std::string cmCurlSetCAInfo(::CURL* curl, const char* cafile = nullptr);
+std::string cmCurlSetCAInfo(::CURL* curl, const std::string& cafile = {});
 std::string cmCurlSetNETRCOption(::CURL* curl, const std::string& netrc_level,
                                  const std::string& netrc_file);
+std::string cmCurlFixFileURL(std::string url);
index 5a2683b..fd0a63c 100644 (file)
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTransformDepfile.h"
+#include "cmValue.h"
 
 namespace {
 std::string EvaluateSplitConfigGenex(
@@ -91,7 +91,7 @@ std::string EvaluateSplitConfigGenex(
 
     // Record targets referenced by the genex.
     if (utils) {
-      // FIXME: What is the proper condition for a cross-dependency?
+      // Use a cross-dependency if we referenced the command config.
       bool const cross = !useOutputConfig;
       for (cmGeneratorTarget* gt : cge->GetTargets()) {
         utils->emplace(BT<std::pair<std::string, bool>>(
@@ -176,6 +176,8 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(
   cmGeneratorTarget const* target{ lg->FindGeneratorTargetToUse(
     this->Target) };
 
+  bool const distinctConfigs = this->OutputConfig != this->CommandConfig;
+
   const cmCustomCommandLines& cmdlines = this->CC->GetCommandLines();
   for (cmCustomCommandLine const& cmdline : cmdlines) {
     cmCustomCommandLine argv;
@@ -191,8 +193,10 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(
         argv.push_back(std::move(parsed_arg));
       }
 
-      // For remaining arguments, we default to the OUTPUT_CONFIG.
-      useOutputConfig = true;
+      if (distinctConfigs) {
+        // For remaining arguments, we default to the OUTPUT_CONFIG.
+        useOutputConfig = true;
+      }
     }
 
     if (!argv.empty()) {
@@ -200,7 +204,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(
       // collect the target to add a target-level dependency on it.
       cmGeneratorTarget* gt = this->LG->FindGeneratorTargetToUse(argv.front());
       if (gt && gt->GetType() == cmStateEnums::EXECUTABLE) {
-        // FIXME: What is the proper condition for a cross-dependency?
+        // GetArgv0Location uses the command config, so use a cross-dependency.
         bool const cross = true;
         this->Utilities.emplace(BT<std::pair<std::string, bool>>(
           { gt->GetName(), cross }, cc.GetBacktrace()));
@@ -284,7 +288,7 @@ void cmCustomCommandGenerator::FillEmulatorsWithArguments()
     if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
         !target->IsImported()) {
 
-      cmProp emulator_property =
+      cmValue emulator_property =
         target->GetProperty("CROSSCOMPILING_EMULATOR");
       if (!emulator_property) {
         continue;
index 4a4f87d..a5f8aab 100644 (file)
@@ -34,11 +34,11 @@ cmDefinitions::Def const& cmDefinitions::GetInternal(const std::string& key,
   return begin->Map.emplace(key, def).first->second;
 }
 
-const std::string* cmDefinitions::Get(const std::string& key, StackIter begin,
-                                      StackIter end)
+cmValue cmDefinitions::Get(const std::string& key, StackIter begin,
+                           StackIter end)
 {
   Def const& def = cmDefinitions::GetInternal(key, begin, end, false);
-  return def.Value ? def.Value.str_if_stable() : nullptr;
+  return def.Value ? cmValue(def.Value.str_if_stable()) : nullptr;
 }
 
 void cmDefinitions::Raise(const std::string& key, StackIter begin,
index b650aa8..22fef80 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "cmLinkedTree.h"
 #include "cmString.hxx"
+#include "cmValue.h"
 
 /** \class cmDefinitions
  * \brief Store a scope of variable definitions for CMake language.
@@ -28,8 +29,7 @@ class cmDefinitions
 public:
   // -- Static member functions
 
-  static const std::string* Get(const std::string& key, StackIter begin,
-                                StackIter end);
+  static cmValue Get(const std::string& key, StackIter begin, StackIter end);
 
   static void Raise(const std::string& key, StackIter begin, StackIter end);
 
index 46c7e3e..eca1abd 100644 (file)
@@ -11,9 +11,9 @@
 #include "cmGeneratedFileStream.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmDepends::cmDepends(cmLocalUnixMakefileGenerator3* lg, std::string targetDir)
   : LocalGenerator(lg)
@@ -232,7 +232,7 @@ void cmDepends::SetIncludePathFromLanguage(const std::string& lang)
   std::string includePathVar =
     cmStrCat("CMAKE_", lang, "_TARGET_INCLUDE_PATH");
   cmMakefile* mf = this->LocalGenerator->GetMakefile();
-  cmProp includePath = mf->GetDefinition(includePathVar);
+  cmValue includePath = mf->GetDefinition(includePathVar);
   if (includePath) {
     cmExpandList(*includePath, this->IncludePath);
   } else {
index da37d45..2527809 100644 (file)
@@ -10,9 +10,9 @@
 #include "cmGlobalUnixMakefileGenerator3.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 #define INCLUDE_REGEX_LINE                                                    \
   "^[ \t]*[#%][ \t]*(include|import)[ \t]*[<\"]([^\">]+)([\">])"
@@ -40,12 +40,12 @@ cmDependsC::cmDependsC(cmLocalUnixMakefileGenerator3* lg,
   std::string complainRegex = "^$";
   {
     std::string scanRegexVar = cmStrCat("CMAKE_", lang, "_INCLUDE_REGEX_SCAN");
-    if (cmProp sr = mf->GetDefinition(scanRegexVar)) {
+    if (cmValue sr = mf->GetDefinition(scanRegexVar)) {
       scanRegex = *sr;
     }
     std::string complainRegexVar =
       cmStrCat("CMAKE_", lang, "_INCLUDE_REGEX_COMPLAIN");
-    if (cmProp cr = mf->GetDefinition(complainRegexVar)) {
+    if (cmValue cr = mf->GetDefinition(complainRegexVar)) {
       complainRegex = *cr;
     }
   }
index a64dc27..d5e54ae 100644 (file)
@@ -16,9 +16,9 @@
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 // TODO: Test compiler for the case of the mod file.  Some always
 // use lower case and some always use upper case.  I do not know if any
@@ -163,12 +163,17 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends,
     mod_dir = this->LocalGenerator->GetCurrentBinaryDirectory();
   }
 
+  bool building_intrinsics =
+    !mf->GetSafeDefinition("CMAKE_Fortran_TARGET_BUILDING_INSTRINSIC_MODULES")
+       .empty();
+
   // Actually write dependencies to the streams.
   using ObjectInfoMap = cmDependsFortranInternals::ObjectInfoMap;
   ObjectInfoMap const& objInfo = this->Internal->ObjectInfo;
   for (auto const& i : objInfo) {
     if (!this->WriteDependenciesReal(i.first, i.second, mod_dir, stamp_dir,
-                                     makeDepends, internalDepends)) {
+                                     makeDepends, internalDepends,
+                                     building_intrinsics)) {
       return false;
     }
   }
@@ -307,7 +312,8 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj,
                                              std::string const& mod_dir,
                                              std::string const& stamp_dir,
                                              std::ostream& makeDepends,
-                                             std::ostream& internalDepends)
+                                             std::ostream& internalDepends,
+                                             bool buildingIntrinsics)
 {
   // Get the source file for this object.
   std::string const& src = info.Source;
@@ -339,8 +345,13 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj,
     makeDepends << '\n';
   }
 
+  std::set<std::string> req = info.Requires;
+  if (buildingIntrinsics) {
+    req.insert(info.Intrinsics.begin(), info.Intrinsics.end());
+  }
+
   // Write module requirements to the output stream.
-  for (std::string const& i : info.Requires) {
+  for (std::string const& i : req) {
     // Require only modules not provided in the same source.
     if (info.Provides.find(i) != info.Provides.cend()) {
       continue;
@@ -405,7 +416,7 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj,
       makeDepends << "\t$(CMAKE_COMMAND) -E cmake_copy_f90_mod " << modFile
                   << ' ' << stampFileForShell;
       cmMakefile* mf = this->LocalGenerator->GetMakefile();
-      cmProp cid = mf->GetDefinition("CMAKE_Fortran_COMPILER_ID");
+      cmValue cid = mf->GetDefinition("CMAKE_Fortran_COMPILER_ID");
       if (cmNonempty(cid)) {
         makeDepends << ' ' << *cid;
       }
index 0d407bc..a74db91 100644 (file)
@@ -72,7 +72,8 @@ protected:
                              std::string const& mod_dir,
                              std::string const& stamp_dir,
                              std::ostream& makeDepends,
-                             std::ostream& internalDepends);
+                             std::ostream& internalDepends,
+                             bool buildingIntrinsics);
 
   // The source file from which to start scanning.
   std::string SourceFile;
index 9a474e3..1678ce8 100644 (file)
 
 #include "cmsys/FStream.hxx"
 
-// Include the ELF format information system header.
-#if defined(__OpenBSD__)
-#  include <elf_abi.h>
-#elif defined(__HAIKU__)
-#  include <elf32.h>
-#  include <elf64.h>
-using Elf32_Ehdr = struct Elf32_Ehdr;
-using Elf32_Shdr = struct Elf32_Shdr;
-using Elf32_Sym = struct Elf32_Sym;
-using Elf32_Rel = struct Elf32_Rel;
-using Elf32_Rela = struct Elf32_Rela;
-#  define ELFMAG0 0x7F
-#  define ELFMAG1 'E'
-#  define ELFMAG2 'L'
-#  define ELFMAG3 'F'
-#  define ET_NONE 0
-#  define ET_REL 1
-#  define ET_EXEC 2
-#  define ET_DYN 3
-#  define ET_CORE 4
-#  define EM_386 3
-#  define EM_SPARC 2
-#  define EM_PPC 20
-#else
-#  include <elf.h>
-#endif
-#if defined(__sun)
-#  include <sys/link.h> // For dynamic section information
-#endif
-#ifdef _SCO_DS
-#  include <link.h> // For DT_SONAME etc.
-#endif
-#ifndef DT_RUNPATH
-#  define DT_RUNPATH 29
-#endif
+#include "cmelf/elf32.h"
+#include "cmelf/elf64.h"
+#include "cmelf/elf_common.h"
 
 // Low-level byte swapping implementation.
 template <size_t s>
@@ -145,6 +113,7 @@ public:
   virtual std::vector<char> EncodeDynamicEntries(
     const cmELF::DynamicEntryList&) = 0;
   virtual StringEntry const* GetDynamicSectionString(unsigned int tag) = 0;
+  virtual bool IsMips() const = 0;
   virtual void PrintInfo(std::ostream& os) const = 0;
 
   // Lookup the SONAME in the DYNAMIC section.
@@ -218,7 +187,6 @@ struct cmELFTypes32
 };
 
 // Configure the implementation template for 64-bit ELF files.
-#ifndef _SCO_DS
 struct cmELFTypes64
 {
   using ELF_Ehdr = Elf64_Ehdr;
@@ -228,7 +196,6 @@ struct cmELFTypes64
   using tagtype = ::uint64_t;
   static const char* GetName() { return "64-bit"; }
 };
-#endif
 
 // Parser implementation template.
 template <class Types>
@@ -262,6 +229,8 @@ public:
   // Lookup a string from the dynamic section with the given tag.
   StringEntry const* GetDynamicSectionString(unsigned int tag) override;
 
+  bool IsMips() const override { return this->ELFHeader.e_machine == EM_MIPS; }
+
   // Print information about the ELF file.
   void PrintInfo(std::ostream& os) const override
   {
@@ -345,16 +314,12 @@ private:
         eti == ET_CORE) {
       return true;
     }
-#if defined(ET_LOOS) && defined(ET_HIOS)
     if (eti >= ET_LOOS && eti <= ET_HIOS) {
       return true;
     }
-#endif
-#if defined(ET_LOPROC) && defined(ET_HIPROC)
     if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
       return true;
     }
-#endif
     return false;
   }
 
@@ -465,18 +430,14 @@ cmELFInternalImpl<Types>::cmELFInternalImpl(cmELF* external,
       break;
     default: {
       unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type);
-#if defined(ET_LOOS) && defined(ET_HIOS)
       if (eti >= ET_LOOS && eti <= ET_HIOS) {
         this->ELFType = cmELF::FileTypeSpecificOS;
         break;
       }
-#endif
-#if defined(ET_LOPROC) && defined(ET_HIPROC)
       if (eti >= ET_LOPROC && eti <= ET_HIPROC) {
         this->ELFType = cmELF::FileTypeSpecificProc;
         break;
       }
-#endif
       std::ostringstream e;
       e << "Unknown ELF file type " << eti;
       this->SetErrorMessage(e.str().c_str());
@@ -681,17 +642,12 @@ cmELF::StringEntry const* cmELFInternalImpl<Types>::GetDynamicSectionString(
 
 const long cmELF::TagRPath = DT_RPATH;
 const long cmELF::TagRunPath = DT_RUNPATH;
-
-#ifdef DT_MIPS_RLD_MAP_REL
 const long cmELF::TagMipsRldMapRel = DT_MIPS_RLD_MAP_REL;
-#else
-const long cmELF::TagMipsRldMapRel = 0;
-#endif
 
 cmELF::cmELF(const char* fname)
 {
   // Try to open the file.
-  auto fin = cm::make_unique<cmsys::ifstream>(fname);
+  auto fin = cm::make_unique<cmsys::ifstream>(fname, std::ios::binary);
 
   // Quit now if the file could not be opened.
   if (!fin || !*fin) {
@@ -736,15 +692,11 @@ cmELF::cmELF(const char* fname)
     // 32-bit ELF
     this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes32>>(
       this, std::move(fin), order);
-  }
-#ifndef _SCO_DS
-  else if (ident[EI_CLASS] == ELFCLASS64) {
+  } else if (ident[EI_CLASS] == ELFCLASS64) {
     // 64-bit ELF
     this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes64>>(
       this, std::move(fin), order);
-  }
-#endif
-  else {
+  } else {
     this->ErrorMessage = "ELF file class is not 32-bit or 64-bit.";
     return;
   }
@@ -846,6 +798,14 @@ cmELF::StringEntry const* cmELF::GetRunPath()
   return nullptr;
 }
 
+bool cmELF::IsMIPS() const
+{
+  if (this->Valid()) {
+    return this->Internal->IsMips();
+  }
+  return false;
+}
+
 void cmELF::PrintInfo(std::ostream& os) const
 {
   if (this->Valid()) {
index f88ebe9..ce8bd7f 100644 (file)
 #include <utility>
 #include <vector>
 
-#if !defined(CMake_USE_ELF_PARSER)
-#  error "This file may be included only if CMake_USE_ELF_PARSER is enabled."
-#endif
-
 class cmELFInternal;
 
 /** \class cmELF
@@ -102,6 +98,9 @@ public:
   /** Get the RUNPATH field if any.  */
   StringEntry const* GetRunPath();
 
+  /** Returns true if the ELF file targets a MIPS CPU.  */
+  bool IsMIPS() const;
+
   /** Print human-readable information about the ELF file.  */
   void PrintInfo(std::ostream& os) const;
 
index 1a31ae4..aa968dc 100644 (file)
@@ -22,6 +22,7 @@
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"
 #include "cmTargetExport.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 class cmSourceFile;
@@ -254,7 +255,7 @@ void cmExportBuildFileGenerator::SetImportLocationProperty(
 
 void cmExportBuildFileGenerator::HandleMissingTarget(
   std::string& link_libs, std::vector<std::string>& missingTargets,
-  cmGeneratorTarget* depender, cmGeneratorTarget* dependee)
+  cmGeneratorTarget const* depender, cmGeneratorTarget* dependee)
 {
   // The target is not in the export.
   if (!this->AppendMode) {
@@ -321,7 +322,7 @@ cmExportBuildFileGenerator::FindBuildExportInfo(cmGlobalGenerator* gg,
 }
 
 void cmExportBuildFileGenerator::ComplainAboutMissingTarget(
-  cmGeneratorTarget* depender, cmGeneratorTarget* dependee,
+  cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
   std::vector<std::string> const& exportFiles)
 {
   std::ostringstream e;
@@ -344,7 +345,7 @@ void cmExportBuildFileGenerator::ComplainAboutMissingTarget(
 }
 
 std::string cmExportBuildFileGenerator::InstallNameDir(
-  cmGeneratorTarget* target, const std::string& config)
+  cmGeneratorTarget const* target, const std::string& config)
 {
   std::string install_name_dir;
 
index 264494d..244f526 100644 (file)
@@ -60,11 +60,11 @@ protected:
     cmGeneratorTarget const* target) const;
   void HandleMissingTarget(std::string& link_libs,
                            std::vector<std::string>& missingTargets,
-                           cmGeneratorTarget* depender,
+                           cmGeneratorTarget const* depender,
                            cmGeneratorTarget* dependee) override;
 
-  void ComplainAboutMissingTarget(cmGeneratorTarget* depender,
-                                  cmGeneratorTarget* dependee,
+  void ComplainAboutMissingTarget(cmGeneratorTarget const* depender,
+                                  cmGeneratorTarget const* dependee,
                                   std::vector<std::string> const& namespaces);
 
   /** Fill in properties indicating built file locations.  */
@@ -73,7 +73,7 @@ protected:
                                  cmGeneratorTarget* target,
                                  ImportPropertyMap& properties);
 
-  std::string InstallNameDir(cmGeneratorTarget* target,
+  std::string InstallNameDir(cmGeneratorTarget const* target,
                              const std::string& config) override;
 
   std::pair<std::vector<std::string>, std::string> FindBuildExportInfo(
index 352eaf2..63440a3 100644 (file)
@@ -282,6 +282,7 @@ static bool HandlePackage(std::vector<std::string> const& args,
   // CMP0090 decides both the default and what variable changes it.
   switch (mf.GetPolicyStatus(cmPolicies::CMP0090)) {
     case cmPolicies::WARN:
+      CM_FALLTHROUGH;
     case cmPolicies::OLD:
       // Default is to export, but can be disabled.
       if (mf.IsOn("CMAKE_EXPORT_NO_PACKAGE_REGISTRY")) {
index dd611de..8ca9a66 100644 (file)
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmPropertyMap.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
-#include "cmTargetExport.h"
+#include "cmValue.h"
 
 static std::string cmExportFileGeneratorEscape(std::string const& str)
 {
@@ -123,10 +122,10 @@ void cmExportFileGenerator::GenerateImportConfig(
 }
 
 void cmExportFileGenerator::PopulateInterfaceProperty(
-  const std::string& propName, cmGeneratorTarget* target,
+  const std::string& propName, cmGeneratorTarget const* target,
   ImportPropertyMap& properties)
 {
-  cmProp input = target->GetProperty(propName);
+  cmValue input = target->GetProperty(propName);
   if (input) {
     properties[propName] = *input;
   }
@@ -134,11 +133,11 @@ void cmExportFileGenerator::PopulateInterfaceProperty(
 
 void cmExportFileGenerator::PopulateInterfaceProperty(
   const std::string& propName, const std::string& outputName,
-  cmGeneratorTarget* target,
+  cmGeneratorTarget const* target,
   cmGeneratorExpression::PreprocessContext preprocessRule,
   ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
 {
-  cmProp input = target->GetProperty(propName);
+  cmValue input = target->GetProperty(propName);
   if (input) {
     if (input->empty()) {
       // Set to empty
@@ -168,14 +167,14 @@ void cmExportFileGenerator::GenerateRequiredCMakeVersion(
 }
 
 bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty(
-  cmGeneratorTarget* target,
+  cmGeneratorTarget const* target,
   cmGeneratorExpression::PreprocessContext preprocessRule,
   ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
 {
   if (!target->IsLinkable()) {
     return false;
   }
-  cmProp input = target->GetProperty("INTERFACE_LINK_LIBRARIES");
+  cmValue input = target->GetProperty("INTERFACE_LINK_LIBRARIES");
   if (input) {
     std::string prepro =
       cmGeneratorExpression::Preprocess(*input, preprocessRule);
@@ -196,7 +195,7 @@ static bool isSubDirectory(std::string const& a, std::string const& b)
 }
 
 static bool checkInterfaceDirs(const std::string& prepro,
-                               cmGeneratorTarget* target,
+                               cmGeneratorTarget const* target,
                                const std::string& prop)
 {
   std::string const& installDir =
@@ -335,14 +334,14 @@ static void prefixItems(std::string& exportDirs)
 }
 
 void cmExportFileGenerator::PopulateSourcesInterface(
-  cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
+  cmGeneratorTarget const* gt,
+  cmGeneratorExpression::PreprocessContext preprocessRule,
   ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
 {
-  cmGeneratorTarget* gt = tei->Target;
   assert(preprocessRule == cmGeneratorExpression::InstallInterface);
 
   const char* propName = "INTERFACE_SOURCES";
-  cmProp input = gt->GetProperty(propName);
+  cmValue input = gt->GetProperty(propName);
 
   if (!input) {
     return;
@@ -366,19 +365,20 @@ void cmExportFileGenerator::PopulateSourcesInterface(
 }
 
 void cmExportFileGenerator::PopulateIncludeDirectoriesInterface(
-  cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
+  cmGeneratorTarget const* target,
+  cmGeneratorExpression::PreprocessContext preprocessRule,
   ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
 {
-  cmGeneratorTarget* target = tei->Target;
   assert(preprocessRule == cmGeneratorExpression::InstallInterface);
 
   const char* propName = "INTERFACE_INCLUDE_DIRECTORIES";
-  cmProp input = target->GetProperty(propName);
+  cmValue input = target->GetProperty(propName);
 
   cmGeneratorExpression ge;
 
   std::string dirs = cmGeneratorExpression::Preprocess(
-    tei->InterfaceIncludeDirectories, preprocessRule, true);
+    cmJoin(target->Target->GetInstallIncludeDirectoriesEntries(), ";"),
+    preprocessRule, true);
   this->ReplaceInstallPrefix(dirs);
   std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(dirs);
   std::string exportDirs =
@@ -424,14 +424,14 @@ void cmExportFileGenerator::PopulateIncludeDirectoriesInterface(
 }
 
 void cmExportFileGenerator::PopulateLinkDependsInterface(
-  cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
+  cmGeneratorTarget const* gt,
+  cmGeneratorExpression::PreprocessContext preprocessRule,
   ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
 {
-  cmGeneratorTarget* gt = tei->Target;
   assert(preprocessRule == cmGeneratorExpression::InstallInterface);
 
   const char* propName = "INTERFACE_LINK_DEPENDS";
-  cmProp input = gt->GetProperty(propName);
+  cmValue input = gt->GetProperty(propName);
 
   if (!input) {
     return;
@@ -455,14 +455,14 @@ void cmExportFileGenerator::PopulateLinkDependsInterface(
 }
 
 void cmExportFileGenerator::PopulateLinkDirectoriesInterface(
-  cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
+  cmGeneratorTarget const* gt,
+  cmGeneratorExpression::PreprocessContext preprocessRule,
   ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
 {
-  cmGeneratorTarget* gt = tei->Target;
   assert(preprocessRule == cmGeneratorExpression::InstallInterface);
 
   const char* propName = "INTERFACE_LINK_DIRECTORIES";
-  cmProp input = gt->GetProperty(propName);
+  cmValue input = gt->GetProperty(propName);
 
   if (!input) {
     return;
@@ -486,7 +486,7 @@ void cmExportFileGenerator::PopulateLinkDirectoriesInterface(
 }
 
 void cmExportFileGenerator::PopulateInterfaceProperty(
-  const std::string& propName, cmGeneratorTarget* target,
+  const std::string& propName, cmGeneratorTarget const* target,
   cmGeneratorExpression::PreprocessContext preprocessRule,
   ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
 {
@@ -497,7 +497,7 @@ void cmExportFileGenerator::PopulateInterfaceProperty(
 void getPropertyContents(cmGeneratorTarget const* tgt, const std::string& prop,
                          std::set<std::string>& ifaceProperties)
 {
-  cmProp p = tgt->GetProperty(prop);
+  cmValue p = tgt->GetProperty(prop);
   if (!p) {
     return;
   }
@@ -505,7 +505,7 @@ void getPropertyContents(cmGeneratorTarget const* tgt, const std::string& prop,
   ifaceProperties.insert(content.begin(), content.end());
 }
 
-void getCompatibleInterfaceProperties(cmGeneratorTarget* target,
+void getCompatibleInterfaceProperties(cmGeneratorTarget const* target,
                                       std::set<std::string>& ifaceProperties,
                                       const std::string& config)
 {
@@ -544,7 +544,7 @@ void getCompatibleInterfaceProperties(cmGeneratorTarget* target,
 }
 
 void cmExportFileGenerator::PopulateCompatibleInterfaceProperties(
-  cmGeneratorTarget* gtarget, ImportPropertyMap& properties)
+  cmGeneratorTarget const* gtarget, ImportPropertyMap& properties)
 {
   this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_BOOL", gtarget,
                                   properties);
@@ -596,7 +596,7 @@ void cmExportFileGenerator::GenerateInterfaceProperties(
 }
 
 bool cmExportFileGenerator::AddTargetNamespace(
-  std::string& input, cmGeneratorTarget* target,
+  std::string& input, cmGeneratorTarget const* target,
   std::vector<std::string>& missingTargets)
 {
   cmGeneratorTarget::TargetOrString resolved =
@@ -627,7 +627,7 @@ bool cmExportFileGenerator::AddTargetNamespace(
 }
 
 void cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
-  std::string& input, cmGeneratorTarget* target,
+  std::string& input, cmGeneratorTarget const* target,
   std::vector<std::string>& missingTargets, FreeTargetsReplace replace)
 {
   if (replace == NoReplaceFreeTargets) {
@@ -654,7 +654,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
 }
 
 void cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
-  std::string& input, cmGeneratorTarget* target,
+  std::string& input, cmGeneratorTarget const* target,
   std::vector<std::string>& missingTargets)
 {
   std::string::size_type pos = 0;
@@ -744,7 +744,7 @@ void cmExportFileGenerator::ReplaceInstallPrefix(std::string& /*unused*/)
 void cmExportFileGenerator::SetImportLinkInterface(
   const std::string& config, std::string const& suffix,
   cmGeneratorExpression::PreprocessContext preprocessRule,
-  cmGeneratorTarget* target, ImportPropertyMap& properties,
+  cmGeneratorTarget const* target, ImportPropertyMap& properties,
   std::vector<std::string>& missingTargets)
 {
   // Add the transitive link dependencies for this configuration.
@@ -761,12 +761,12 @@ void cmExportFileGenerator::SetImportLinkInterface(
     return;
   }
 
-  cmProp propContent;
+  cmValue propContent;
 
-  if (cmProp prop_suffixed =
+  if (cmValue prop_suffixed =
         target->GetProperty("LINK_INTERFACE_LIBRARIES" + suffix)) {
     propContent = prop_suffixed;
-  } else if (cmProp prop = target->GetProperty("LINK_INTERFACE_LIBRARIES")) {
+  } else if (cmValue prop = target->GetProperty("LINK_INTERFACE_LIBRARIES")) {
     propContent = prop;
   } else {
     return;
@@ -854,7 +854,7 @@ void cmExportFileGenerator::SetImportDetailProperties(
       cmGeneratorTarget::ManagedType::Native) {
     std::string prop = cmStrCat("IMPORTED_COMMON_LANGUAGE_RUNTIME", suffix);
     std::string propval;
-    if (cmProp p = target->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
+    if (cmValue p = target->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
       propval = *p;
     } else if (target->IsCSharpOnly()) {
       // C# projects do not have the /clr flag, so we set the property
@@ -880,7 +880,7 @@ static std::string const& asString(cmLinkItem const& l)
 
 template <typename T>
 void cmExportFileGenerator::SetImportLinkProperty(
-  std::string const& suffix, cmGeneratorTarget* target,
+  std::string const& suffix, cmGeneratorTarget const* target,
   const std::string& propName, std::vector<T> const& entries,
   ImportPropertyMap& properties, std::vector<std::string>& missingTargets,
   ImportLinkPropertyTargetNames targetNames)
@@ -917,20 +917,20 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os)
   // Protect that file against use with older CMake versions.
   /* clang-format off */
   os << "# Generated by CMake\n\n";
-  os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n"
+  os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.6)\n"
      << "   message(FATAL_ERROR \"CMake >= 2.6.0 required\")\n"
      << "endif()\n";
   /* clang-format on */
 
   // Isolate the file policy level.
   // Support CMake versions as far back as 2.6 but also support using NEW
-  // policy settings for up to CMake 3.19 (this upper limit may be reviewed
+  // policy settings for up to CMake 3.20 (this upper limit may be reviewed
   // and increased from time to time). This reduces the opportunity for CMake
   // warnings when an older export file is later used with newer CMake
   // versions.
   /* clang-format off */
   os << "cmake_policy(PUSH)\n"
-     << "cmake_policy(VERSION 2.6...3.19)\n";
+     << "cmake_policy(VERSION 2.6...3.20)\n";
   /* clang-format on */
 }
 
@@ -1211,11 +1211,11 @@ void cmExportFileGenerator::GenerateImportedFileChecksCode(
 }
 
 bool cmExportFileGenerator::PopulateExportProperties(
-  cmGeneratorTarget* gte, ImportPropertyMap& properties,
+  cmGeneratorTarget const* gte, ImportPropertyMap& properties,
   std::string& errorMessage)
 {
   const auto& targetProperties = gte->Target->GetProperties();
-  if (cmProp exportProperties =
+  if (cmValue exportProperties =
         targetProperties.GetPropertyValue("EXPORT_PROPERTIES")) {
     for (auto& prop : cmExpandedList(*exportProperties)) {
       /* Black list reserved properties */
@@ -1228,7 +1228,7 @@ bool cmExportFileGenerator::PopulateExportProperties(
         errorMessage = e.str();
         return false;
       }
-      cmProp propertyValue = targetProperties.GetPropertyValue(prop);
+      cmValue propertyValue = targetProperties.GetPropertyValue(prop);
       if (!propertyValue) {
         // Asked to export a property that isn't defined on the target. Do not
         // consider this an error, there's just nothing to export.
index 45eaed0..24e048b 100644 (file)
@@ -27,8 +27,6 @@ class cmGeneratorTarget;
          CMake_VERSION_MINOR) "." STRINGIFY(CMake_VERSION_PATCH)              \
      : #major "." #minor ".0")
 
-class cmTargetExport;
-
 /** \class cmExportFileGenerator
  * \brief Generate a file exporting targets from a build or install tree.
  *
@@ -108,7 +106,7 @@ protected:
   };
   template <typename T>
   void SetImportLinkProperty(std::string const& suffix,
-                             cmGeneratorTarget* target,
+                             cmGeneratorTarget const* target,
                              const std::string& propName,
                              std::vector<T> const& entries,
                              ImportPropertyMap& properties,
@@ -127,44 +125,45 @@ protected:
    *  export set.  */
   virtual void HandleMissingTarget(std::string& link_libs,
                                    std::vector<std::string>& missingTargets,
-                                   cmGeneratorTarget* depender,
+                                   cmGeneratorTarget const* depender,
                                    cmGeneratorTarget* dependee) = 0;
-  void PopulateInterfaceProperty(const std::string&, cmGeneratorTarget* target,
+  void PopulateInterfaceProperty(const std::string&,
+                                 cmGeneratorTarget const* target,
                                  cmGeneratorExpression::PreprocessContext,
                                  ImportPropertyMap& properties,
                                  std::vector<std::string>& missingTargets);
   bool PopulateInterfaceLinkLibrariesProperty(
-    cmGeneratorTarget* target, cmGeneratorExpression::PreprocessContext,
+    cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext,
     ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
   void PopulateInterfaceProperty(const std::string& propName,
-                                 cmGeneratorTarget* target,
+                                 cmGeneratorTarget const* target,
                                  ImportPropertyMap& properties);
-  void PopulateCompatibleInterfaceProperties(cmGeneratorTarget* target,
+  void PopulateCompatibleInterfaceProperties(cmGeneratorTarget const* target,
                                              ImportPropertyMap& properties);
   virtual void GenerateInterfaceProperties(
     cmGeneratorTarget const* target, std::ostream& os,
     const ImportPropertyMap& properties);
   void PopulateIncludeDirectoriesInterface(
-    cmTargetExport* target,
+    cmGeneratorTarget const* target,
     cmGeneratorExpression::PreprocessContext preprocessRule,
     ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
   void PopulateSourcesInterface(
-    cmTargetExport* target,
+    cmGeneratorTarget const* target,
     cmGeneratorExpression::PreprocessContext preprocessRule,
     ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
   void PopulateLinkDirectoriesInterface(
-    cmTargetExport* target,
+    cmGeneratorTarget const* target,
     cmGeneratorExpression::PreprocessContext preprocessRule,
     ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
   void PopulateLinkDependsInterface(
-    cmTargetExport* target,
+    cmGeneratorTarget const* target,
     cmGeneratorExpression::PreprocessContext preprocessRule,
     ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
 
   void SetImportLinkInterface(
     const std::string& config, std::string const& suffix,
     cmGeneratorExpression::PreprocessContext preprocessRule,
-    cmGeneratorTarget* target, ImportPropertyMap& properties,
+    cmGeneratorTarget const* target, ImportPropertyMap& properties,
     std::vector<std::string>& missingTargets);
 
   enum FreeTargetsReplace
@@ -174,14 +173,14 @@ protected:
   };
 
   void ResolveTargetsInGeneratorExpressions(
-    std::string& input, cmGeneratorTarget* target,
+    std::string& input, cmGeneratorTarget const* target,
     std::vector<std::string>& missingTargets,
     FreeTargetsReplace replace = NoReplaceFreeTargets);
 
   virtual void GenerateRequiredCMakeVersion(std::ostream& os,
                                             const char* versionString);
 
-  bool PopulateExportProperties(cmGeneratorTarget* gte,
+  bool PopulateExportProperties(cmGeneratorTarget const* gte,
                                 ImportPropertyMap& properties,
                                 std::string& errorMessage);
 
@@ -205,20 +204,20 @@ protected:
 
 private:
   void PopulateInterfaceProperty(const std::string&, const std::string&,
-                                 cmGeneratorTarget* target,
+                                 cmGeneratorTarget const* target,
                                  cmGeneratorExpression::PreprocessContext,
                                  ImportPropertyMap& properties,
                                  std::vector<std::string>& missingTargets);
 
-  bool AddTargetNamespace(std::string& input, cmGeneratorTarget* target,
+  bool AddTargetNamespace(std::string& input, cmGeneratorTarget const* target,
                           std::vector<std::string>& missingTargets);
 
   void ResolveTargetsInGeneratorExpression(
-    std::string& input, cmGeneratorTarget* target,
+    std::string& input, cmGeneratorTarget const* target,
     std::vector<std::string>& missingTargets);
 
   virtual void ReplaceInstallPrefix(std::string& input);
 
-  virtual std::string InstallNameDir(cmGeneratorTarget* target,
+  virtual std::string InstallNameDir(cmGeneratorTarget const* target,
                                      const std::string& config) = 0;
 };
index 3c69c50..e9ac875 100644 (file)
@@ -21,6 +21,7 @@
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTargetExport.h"
+#include "cmValue.h"
 
 cmExportInstallFileGenerator::cmExportInstallFileGenerator(
   cmInstallExportGenerator* iegen)
@@ -85,8 +86,8 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
     ImportPropertyMap properties;
 
     this->PopulateIncludeDirectoriesInterface(
-      te, cmGeneratorExpression::InstallInterface, properties, missingTargets);
-    this->PopulateSourcesInterface(te, cmGeneratorExpression::InstallInterface,
+      gt, cmGeneratorExpression::InstallInterface, properties, missingTargets);
+    this->PopulateSourcesInterface(gt, cmGeneratorExpression::InstallInterface,
                                    properties, missingTargets);
     this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt,
                                     cmGeneratorExpression::InstallInterface,
@@ -110,9 +111,9 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
                                     cmGeneratorExpression::InstallInterface,
                                     properties, missingTargets);
     this->PopulateLinkDirectoriesInterface(
-      te, cmGeneratorExpression::InstallInterface, properties, missingTargets);
+      gt, cmGeneratorExpression::InstallInterface, properties, missingTargets);
     this->PopulateLinkDependsInterface(
-      te, cmGeneratorExpression::InstallInterface, properties, missingTargets);
+      gt, cmGeneratorExpression::InstallInterface, properties, missingTargets);
 
     std::string errorMessage;
     if (!this->PopulateExportProperties(gt, properties, errorMessage)) {
@@ -447,7 +448,7 @@ cmStateEnums::TargetType cmExportInstallFileGenerator::GetExportTargetType(
 
 void cmExportInstallFileGenerator::HandleMissingTarget(
   std::string& link_libs, std::vector<std::string>& missingTargets,
-  cmGeneratorTarget* depender, cmGeneratorTarget* dependee)
+  cmGeneratorTarget const* depender, cmGeneratorTarget* dependee)
 {
   const std::string name = dependee->GetName();
   cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator();
@@ -499,7 +500,7 @@ cmExportInstallFileGenerator::FindNamespaces(cmGlobalGenerator* gg,
 }
 
 void cmExportInstallFileGenerator::ComplainAboutMissingTarget(
-  cmGeneratorTarget* depender, cmGeneratorTarget* dependee,
+  cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
   std::vector<std::string> const& exportFiles)
 {
   std::ostringstream e;
@@ -521,7 +522,7 @@ void cmExportInstallFileGenerator::ComplainAboutMissingTarget(
 }
 
 std::string cmExportInstallFileGenerator::InstallNameDir(
-  cmGeneratorTarget* target, const std::string& config)
+  cmGeneratorTarget const* target, const std::string& config)
 {
   std::string install_name_dir;
 
index 2d8de9d..5cec2e0 100644 (file)
@@ -63,13 +63,13 @@ protected:
     cmTargetExport const* targetExport) const;
   void HandleMissingTarget(std::string& link_libs,
                            std::vector<std::string>& missingTargets,
-                           cmGeneratorTarget* depender,
+                           cmGeneratorTarget const* depender,
                            cmGeneratorTarget* dependee) override;
 
   void ReplaceInstallPrefix(std::string& input) override;
 
-  void ComplainAboutMissingTarget(cmGeneratorTarget* depender,
-                                  cmGeneratorTarget* dependee,
+  void ComplainAboutMissingTarget(cmGeneratorTarget const* depender,
+                                  cmGeneratorTarget const* dependee,
                                   std::vector<std::string> const& exportFiles);
 
   std::pair<std::vector<std::string>, std::string> FindNamespaces(
@@ -94,7 +94,7 @@ protected:
                                  ImportPropertyMap& properties,
                                  std::set<std::string>& importedLocations);
 
-  std::string InstallNameDir(cmGeneratorTarget* target,
+  std::string InstallNameDir(cmGeneratorTarget const* target,
                              const std::string& config) override;
 
   cmInstallExportGenerator* IEGen;
index 7f31dd2..8aec12b 100644 (file)
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTargetLinkLibraryType.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 class cmListFileBacktrace;
@@ -96,7 +96,7 @@ static void FinalAction(cmMakefile& makefile, std::string const& filename,
           // Handle simple output name changes.  This command is
           // deprecated so we do not support full target name
           // translation (which requires per-configuration info).
-          if (cmProp outname = libtgt->GetProperty("OUTPUT_NAME")) {
+          if (cmValue outname = libtgt->GetProperty("OUTPUT_NAME")) {
             lib = *outname;
           }
         }
index cac60e1..cbe3c4d 100644 (file)
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 
 cmExportTryCompileFileGenerator::cmExportTryCompileFileGenerator(
   cmGlobalGenerator* gg, const std::vector<std::string>& targets,
@@ -60,7 +60,7 @@ std::string cmExportTryCompileFileGenerator::FindTargets(
   const std::string& propName, cmGeneratorTarget const* tgt,
   std::string const& language, std::set<cmGeneratorTarget const*>& emitted)
 {
-  cmProp prop = tgt->GetProperty(propName);
+  cmValue prop = tgt->GetProperty(propName);
   if (!prop) {
     return std::string();
   }
@@ -126,7 +126,7 @@ void cmExportTryCompileFileGenerator::PopulateProperties(
 }
 
 std::string cmExportTryCompileFileGenerator::InstallNameDir(
-  cmGeneratorTarget* target, const std::string& config)
+  cmGeneratorTarget const* target, const std::string& config)
 {
   std::string install_name_dir;
 
index 6bf5781..127b8df 100644 (file)
@@ -36,7 +36,8 @@ protected:
   {
   }
   void HandleMissingTarget(std::string&, std::vector<std::string>&,
-                           cmGeneratorTarget*, cmGeneratorTarget*) override
+                           cmGeneratorTarget const*,
+                           cmGeneratorTarget*) override
   {
   }
 
@@ -44,7 +45,7 @@ protected:
                           ImportPropertyMap& properties,
                           std::set<const cmGeneratorTarget*>& emitted);
 
-  std::string InstallNameDir(cmGeneratorTarget* target,
+  std::string InstallNameDir(cmGeneratorTarget const* target,
                              const std::string& config) override;
 
 private:
index df14261..e2c54d7 100644 (file)
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmXMLWriter.h"
 #include "cmake.h"
 
@@ -396,8 +396,8 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
             CbpUnit& cbpUnit = allFiles[fullPath];
             cbpUnit.Targets.push_back(target.get());
           }
-        }
-        default: // intended fallthrough
+        } break;
+        default:
           break;
       }
     }
@@ -499,12 +499,12 @@ void cmExtraCodeBlocksGenerator::AppendTarget(
     if (target->GetType() == cmStateEnums::EXECUTABLE) {
       // Determine the directory where the executable target is created, and
       // set the working directory to this dir.
-      cmProp runtimeOutputDir =
+      cmValue runtimeOutputDir =
         makefile->GetDefinition("CMAKE_RUNTIME_OUTPUT_DIRECTORY");
       if (runtimeOutputDir) {
         workingDir = *runtimeOutputDir;
       } else {
-        cmProp executableOutputDir =
+        cmValue executableOutputDir =
           makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
         if (executableOutputDir) {
           workingDir = *executableOutputDir;
index 549b08b..9e8ac5c 100644 (file)
@@ -208,7 +208,7 @@ std::string cmExtraCodeLiteGenerator::CollectSourceFiles(
     case cmStateEnums::MODULE_LIBRARY: {
       projectType = "Dynamic Library";
     } break;
-    default: // intended fallthrough
+    default:
       break;
   }
 
@@ -233,8 +233,8 @@ std::string cmExtraCodeLiteGenerator::CollectSourceFiles(
           otherFiles.insert(fullPath);
         }
       }
-    }
-    default: // intended fallthrough
+    } break;
+    default:
       break;
   }
   return projectType;
@@ -556,7 +556,8 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile(
     case cmStateEnums::SHARED_LIBRARY:
     case cmStateEnums::MODULE_LIBRARY:
       visualname = "lib" + targetName;
-    default: // intended fallthrough
+      break;
+    default:
       break;
   }
   xml.Attribute("Name", visualname);
index 672089c..d9d5a4b 100644 (file)
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmSourceFile.h"
 #include "cmSourceGroup.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmXMLWriter.h"
 #include "cmake.h"
 
@@ -189,7 +189,7 @@ void cmExtraEclipseCDT4Generator::CreateSettingsResourcePrefsFile()
   }
 
   fout << "eclipse.preferences.version=1\n";
-  cmProp encoding = mf->GetDefinition("CMAKE_ECLIPSE_RESOURCE_ENCODING");
+  cmValue encoding = mf->GetDefinition("CMAKE_ECLIPSE_RESOURCE_ENCODING");
   if (encoding) {
     fout << "encoding/<project>=" << *encoding << '\n';
   }
@@ -244,7 +244,7 @@ void cmExtraEclipseCDT4Generator::AddEnvVar(std::ostream& out,
   const bool envVarSet = cmSystemTools::GetEnv(envVar, envVarValue);
 
   std::string cacheEntryName = cmStrCat("CMAKE_ECLIPSE_ENVVAR_", envVar);
-  cmProp cacheValue = lg.GetState()->GetInitializedCacheValue(cacheEntryName);
+  cmValue cacheValue = lg.GetState()->GetInitializedCacheValue(cacheEntryName);
 
   // now we have both, decide which one to use
   std::string valueToUse;
@@ -415,7 +415,7 @@ void cmExtraEclipseCDT4Generator::CreateProjectFile()
     xml.Element("nature", n);
   }
 
-  if (cmProp extraNaturesProp =
+  if (cmValue extraNaturesProp =
         mf->GetState()->GetGlobalProperty("ECLIPSE_EXTRA_NATURES")) {
     std::vector<std::string> extraNatures = cmExpandedList(*extraNaturesProp);
     for (std::string const& n : extraNatures) {
@@ -754,7 +754,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const
   emitted.clear();
   for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) {
 
-    if (cmProp cdefs =
+    if (cmValue cdefs =
           lgen->GetMakefile()->GetProperty("COMPILE_DEFINITIONS")) {
       // Expand the list.
       std::vector<std::string> defs;
@@ -793,7 +793,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const
     }
   }
   // add system defined c macros
-  cmProp cDefs =
+  cmValue cDefs =
     mf->GetDefinition("CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS");
   if (this->CEnabled && cDefs) {
     // Expand the list.
@@ -825,7 +825,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const
     }
   }
   // add system defined c++ macros
-  cmProp cxxDefs =
+  cmValue cxxDefs =
     mf->GetDefinition("CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS");
   if (this->CXXEnabled && cxxDefs) {
     // Expand the list.
@@ -1032,7 +1032,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const
   xml.EndElement(); // storageModule
 
   // Append additional cproject contents without applying any XML formatting
-  if (cmProp extraCProjectContents =
+  if (cmValue extraCProjectContents =
         mf->GetState()->GetGlobalProperty("ECLIPSE_EXTRA_CPROJECT_CONTENTS")) {
     fout << *extraCProjectContents;
   }
index 9153119..eec43c4 100644 (file)
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmSourceFile.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmExtraKateGenerator::cmExtraKateGenerator() = default;
 
@@ -128,7 +128,7 @@ void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator& lg,
             // only add the "edit_cache" target if it's not ccmake, because
             // this will not work within the IDE
             if (targetName == "edit_cache") {
-              cmProp editCommand =
+              cmValue editCommand =
                 localGen->GetMakefile()->GetDefinition("CMAKE_EDIT_COMMAND");
               if (!editCommand ||
                   strstr(editCommand->c_str(), "ccmake") != nullptr) {
index 52965bb..fa93b04 100644 (file)
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmSourceFile.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 /*
@@ -364,12 +364,12 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
                                                     language);
 
   const std::string COMPILE_FLAGS("COMPILE_FLAGS");
-  if (cmProp cflags = source->GetProperty(COMPILE_FLAGS)) {
+  if (cmValue cflags = source->GetProperty(COMPILE_FLAGS)) {
     lg->AppendFlags(flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
   }
 
   const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
-  if (cmProp coptions = source->GetProperty(COMPILE_OPTIONS)) {
+  if (cmValue coptions = source->GetProperty(COMPILE_OPTIONS)) {
     lg->AppendCompileOptions(
       flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
   }
@@ -393,14 +393,14 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines(
   // Add preprocessor definitions for this target and configuration.
   lg->GetTargetDefines(target, config, language, defines);
   const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
-  if (cmProp compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) {
+  if (cmValue compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) {
     lg->AppendDefines(
       defines, genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS));
   }
 
   std::string defPropName =
     cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(config));
-  if (cmProp config_compile_defs = source->GetProperty(defPropName)) {
+  if (cmValue config_compile_defs = source->GetProperty(defPropName)) {
     lg->AppendDefines(
       defines,
       genexInterpreter.Evaluate(*config_compile_defs, COMPILE_DEFINITIONS));
@@ -425,7 +425,7 @@ std::string cmExtraSublimeTextGenerator::ComputeIncludes(
 
   // Add include directories for this source file
   const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
-  if (cmProp cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) {
+  if (cmValue cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) {
     lg->AppendIncludeDirectories(
       includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES),
       *source);
@@ -445,7 +445,7 @@ bool cmExtraSublimeTextGenerator::Open(const std::string& bindir,
                                        const std::string& projectName,
                                        bool dryRun)
 {
-  cmProp sublExecutable =
+  cmValue sublExecutable =
     this->GlobalGenerator->GetCMakeInstance()->GetCacheDefinition(
       "CMAKE_SUBLIMETEXT_EXECUTABLE");
   if (!sublExecutable) {
index ddae527..ba38ef7 100644 (file)
@@ -10,8 +10,8 @@
 #include <cm3p/json/value.h>
 
 #include "cmFileAPI.h"
-#include "cmProperty.h"
 #include "cmState.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 namespace {
@@ -95,7 +95,7 @@ Json::Value Cache::DumpEntryProperty(std::string const& name,
 {
   Json::Value property = Json::objectValue;
   property["name"] = prop;
-  cmProp p = this->State->GetCacheEntryProperty(name, prop);
+  cmValue p = this->State->GetCacheEntryProperty(name, prop);
   property["value"] = p ? *p : "";
   return property;
 }
index a2b5460..147181e 100644 (file)
@@ -41,7 +41,6 @@
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmSourceFile.h"
 #include "cmSourceGroup.h"
 #include "cmState.h"
@@ -53,6 +52,7 @@
 #include "cmTarget.h"
 #include "cmTargetDepend.h"
 #include "cmTargetExport.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 namespace {
@@ -813,8 +813,7 @@ Json::Value CodemodelConfig::DumpProject(Project& p)
 Json::Value CodemodelConfig::DumpMinimumCMakeVersion(cmStateSnapshot s)
 {
   Json::Value minimumCMakeVersion;
-  if (std::string const* def =
-        s.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
+  if (cmValue def = s.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
     minimumCMakeVersion = Json::objectValue;
     minimumCMakeVersion["string"] = *def;
   }
@@ -1188,10 +1187,10 @@ void Target::ProcessLanguage(std::string const& lang)
 {
   CompileData& cd = this->CompileDataMap[lang];
   cd.Language = lang;
-  if (cmProp sysrootCompile =
+  if (cmValue sysrootCompile =
         this->GT->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
     cd.Sysroot = *sysrootCompile;
-  } else if (cmProp sysroot =
+  } else if (cmValue sysroot =
                this->GT->Makefile->GetDefinition("CMAKE_SYSROOT")) {
     cd.Sysroot = *sysroot;
   }
@@ -1260,7 +1259,7 @@ CompileData Target::BuildCompileData(cmSourceFile* sf)
                                                     fd.Language);
 
   const std::string COMPILE_FLAGS("COMPILE_FLAGS");
-  if (cmProp cflags = sf->GetProperty(COMPILE_FLAGS)) {
+  if (cmValue cflags = sf->GetProperty(COMPILE_FLAGS)) {
     std::string flags = genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS);
     fd.Flags.emplace_back(std::move(flags), JBTIndex());
   }
@@ -1354,7 +1353,7 @@ CompileData Target::BuildCompileData(cmSourceFile* sf)
   std::set<std::string> configFileDefines;
   const std::string defPropName =
     "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(this->Config);
-  if (cmProp config_defs = sf->GetProperty(defPropName)) {
+  if (cmValue config_defs = sf->GetProperty(defPropName)) {
     lg->AppendDefines(
       configFileDefines,
       genexInterpreter.Evaluate(*config_defs, COMPILE_DEFINITIONS));
@@ -1740,10 +1739,10 @@ Json::Value Target::DumpLink()
       link["commandFragments"] = std::move(commandFragments);
     }
   }
-  if (cmProp sysrootLink =
+  if (cmValue sysrootLink =
         this->GT->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
     link["sysroot"] = this->DumpSysroot(*sysrootLink);
-  } else if (cmProp sysroot =
+  } else if (cmValue sysroot =
                this->GT->Makefile->GetDefinition("CMAKE_SYSROOT")) {
     link["sysroot"] = this->DumpSysroot(*sysroot);
   }
@@ -1869,7 +1868,7 @@ Json::Value Target::DumpDependency(cmTargetDepend const& td)
 Json::Value Target::DumpFolder()
 {
   Json::Value folder;
-  if (cmProp f = this->GT->GetProperty("FOLDER")) {
+  if (cmValue f = this->GT->GetProperty("FOLDER")) {
     folder = Json::objectValue;
     folder["name"] = *f;
   }
index 722c114..b3540c9 100644 (file)
@@ -11,9 +11,9 @@
 #include "cmFileAPI.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 namespace {
@@ -136,7 +136,7 @@ void Toolchains::DumpToolchainVariable(cmMakefile const* mf,
       object[variable.ObjectKey] = jsonArray;
     }
   } else {
-    cmProp def = mf->GetDefinition(variableName);
+    cmValue def = mf->GetDefinition(variableName);
     if (def) {
       object[variable.ObjectKey] = *def;
     }
index 0ad59c7..fd0595d 100644 (file)
@@ -31,6 +31,7 @@
 #include "cmArgumentParser.h"
 #include "cmCMakePath.h"
 #include "cmCryptoHash.h"
+#include "cmELF.h"
 #include "cmExecutionStatus.h"
 #include "cmFSPermissions.h"
 #include "cmFileCopier.h"
@@ -46,7 +47,6 @@
 #include "cmMessageType.h"
 #include "cmNewLineStyle.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmRuntimeDependencyArchive.h"
 #include "cmState.h"
@@ -54,6 +54,7 @@
 #include "cmSubcommandTable.h"
 #include "cmSystemTools.h"
 #include "cmTimestamp.h"
+#include "cmValue.h"
 #include "cmWorkingDirectory.h"
 #include "cmake.h"
 
 #  include "cmFileLockResult.h"
 #endif
 
-#if defined(CMake_USE_ELF_PARSER)
-#  include "cmELF.h"
-#endif
-
-#if defined(_WIN32)
-#  include <windows.h>
-#endif
-
 namespace {
 
-#if defined(_WIN32)
-// libcurl doesn't support file:// urls for unicode filenames on Windows.
-// Convert string from UTF-8 to ACP if this is a file:// URL.
-std::string fix_file_url_windows(const std::string& url)
-{
-  std::string ret = url;
-  if (strncmp(url.c_str(), "file://", 7) == 0) {
-    std::wstring wurl = cmsys::Encoding::ToWide(url);
-    if (!wurl.empty()) {
-      int mblen =
-        WideCharToMultiByte(CP_ACP, 0, wurl.c_str(), -1, NULL, 0, NULL, NULL);
-      if (mblen > 0) {
-        std::vector<char> chars(mblen);
-        mblen = WideCharToMultiByte(CP_ACP, 0, wurl.c_str(), -1, &chars[0],
-                                    mblen, NULL, NULL);
-        if (mblen > 0) {
-          ret = &chars[0];
-        }
-      }
-    }
-  }
-  return ret;
-}
-#endif
-
 bool HandleWriteImpl(std::vector<std::string> const& args, bool append,
                      cmExecutionStatus& status)
 {
@@ -672,8 +640,9 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse,
       case cmPolicies::NEW:
         g.RecurseThroughSymlinksOff();
         break;
-      case cmPolicies::OLD:
       case cmPolicies::WARN:
+        CM_FALLTHROUGH;
+      case cmPolicies::OLD:
         g.RecurseThroughSymlinksOn();
         break;
     }
@@ -1242,8 +1211,12 @@ bool HandleReadElfCommand(std::vector<std::string> const& args,
     return false;
   }
 
-#if defined(CMake_USE_ELF_PARSER)
   cmELF elf(fileNameArg.c_str());
+  if (!elf) {
+    status.SetError(cmStrCat("READ_ELF given FILE \"", fileNameArg,
+                             "\" that is not a valid ELF file."));
+    return false;
+  }
 
   if (!arguments.RPath.empty()) {
     if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
@@ -1261,15 +1234,6 @@ bool HandleReadElfCommand(std::vector<std::string> const& args,
   }
 
   return true;
-#else
-  std::string error = "ELF parser not available on this platform.";
-  if (arguments.Error.empty()) {
-    status.SetError(error);
-    return false;
-  }
-  status.GetMakefile().AddDefinition(arguments.Error, error);
-  return true;
-#endif
 }
 
 bool HandleInstallCommand(std::vector<std::string> const& args,
@@ -1803,7 +1767,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
   std::string logVar;
   std::string statusVar;
   bool tls_verify = status.GetMakefile().IsOn("CMAKE_TLS_VERIFY");
-  cmProp cainfo = status.GetMakefile().GetDefinition("CMAKE_TLS_CAINFO");
+  cmValue cainfo = status.GetMakefile().GetDefinition("CMAKE_TLS_CAINFO");
   std::string netrc_level =
     status.GetMakefile().GetSafeDefinition("CMAKE_NETRC");
   std::string netrc_file =
@@ -1858,7 +1822,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
     } else if (*i == "TLS_CAINFO") {
       ++i;
       if (i != args.end()) {
-        cainfo = &(*i);
+        cainfo = cmValue(*i);
       } else {
         status.SetError("DOWNLOAD missing file value for TLS_CAINFO.");
         return false;
@@ -1984,9 +1948,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
     }
   }
 
-#  if defined(_WIN32)
-  url = fix_file_url_windows(url);
-#  endif
+  url = cmCurlFixFileURL(url);
 
   ::CURL* curl;
   ::curl_global_init(CURL_GLOBAL_DEFAULT);
@@ -2025,7 +1987,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
 
   // check to see if a CAINFO file has been specified
   // command arg comes first
-  std::string const& cainfo_err = cmCurlSetCAInfo(curl, cmToCStr(cainfo));
+  std::string const& cainfo_err = cmCurlSetCAInfo(curl, cainfo);
   if (!cainfo_err.empty()) {
     status.SetError(cainfo_err);
     return false;
@@ -2191,7 +2153,7 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
   std::string statusVar;
   bool showProgress = false;
   bool tls_verify = status.GetMakefile().IsOn("CMAKE_TLS_VERIFY");
-  cmProp cainfo = status.GetMakefile().GetDefinition("CMAKE_TLS_CAINFO");
+  cmValue cainfo = status.GetMakefile().GetDefinition("CMAKE_TLS_CAINFO");
   std::string userpwd;
   std::string netrc_level =
     status.GetMakefile().GetSafeDefinition("CMAKE_NETRC");
@@ -2244,7 +2206,7 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
     } else if (*i == "TLS_CAINFO") {
       ++i;
       if (i != args.end()) {
-        cainfo = &(*i);
+        cainfo = cmValue(*i);
       } else {
         status.SetError("UPLOAD missing file value for TLS_CAINFO.");
         return false;
@@ -2300,9 +2262,7 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
 
   unsigned long file_size = cmsys::SystemTools::FileLength(filename);
 
-#  if defined(_WIN32)
-  url = fix_file_url_windows(url);
-#  endif
+  url = cmCurlFixFileURL(url);
 
   ::CURL* curl;
   ::curl_global_init(CURL_GLOBAL_DEFAULT);
@@ -2345,7 +2305,7 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
 
   // check to see if a CAINFO file has been specified
   // command arg comes first
-  std::string const& cainfo_err = cmCurlSetCAInfo(curl, cmToCStr(cainfo));
+  std::string const& cainfo_err = cmCurlSetCAInfo(curl, cainfo);
   if (!cainfo_err.empty()) {
     status.SetError(cainfo_err);
     return false;
@@ -3210,9 +3170,12 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
                             archive.GetUnresolvedPaths().begin(),
                             archive.GetUnresolvedPaths().end());
     } else {
-      auto it = archive.GetUnresolvedPaths().begin();
-      assert(it != archive.GetUnresolvedPaths().end());
-      status.SetError(cmStrCat("Could not resolve file ", *it));
+      std::ostringstream e;
+      e << "Could not resolve runtime dependencies:";
+      for (auto const& path : archive.GetUnresolvedPaths()) {
+        e << "\n  " << path;
+      }
+      status.SetError(e.str());
       cmSystemTools::SetFatalErrorOccured();
       return false;
     }
index 237d234..63a4274 100644 (file)
@@ -10,9 +10,9 @@
 #include "cmFSPermissions.h"
 #include "cmFileTimes.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 #ifdef _WIN32
 #  include "cmsys/FStream.hxx"
@@ -172,7 +172,7 @@ void cmFileCopier::DefaultDirectoryPermissions()
 bool cmFileCopier::GetDefaultDirectoryPermissions(mode_t** mode)
 {
   // check if default dir creation permissions were set
-  cmProp default_dir_install_permissions = this->Makefile->GetDefinition(
+  cmValue default_dir_install_permissions = this->Makefile->GetDefinition(
     "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
   if (cmNonempty(default_dir_install_permissions)) {
     std::vector<std::string> items =
index 217d58d..ee9872d 100644 (file)
@@ -67,8 +67,9 @@ protected:
 
   bool InstallSymlinkChain(std::string& fromFile, std::string& toFile);
   bool InstallSymlink(const std::string& fromFile, const std::string& toFile);
-  bool InstallFile(const std::string& fromFile, const std::string& toFile,
-                   MatchProperties match_properties);
+  virtual bool InstallFile(const std::string& fromFile,
+                           const std::string& toFile,
+                           MatchProperties match_properties);
   bool InstallDirectory(const std::string& source,
                         const std::string& destination,
                         MatchProperties match_properties);
index c89be96..9bfbd13 100644 (file)
@@ -3,7 +3,12 @@
 
 #include "cmFileInstaller.h"
 
+#include <map>
 #include <sstream>
+#include <utility>
+
+#include <cm/string_view>
+#include <cmext/string_view>
 
 #include "cm_sys_stat.h"
 
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 using namespace cmFSPermissions;
 
 cmFileInstaller::cmFileInstaller(cmExecutionStatus& status)
   : cmFileCopier(status, "INSTALL")
   , InstallType(cmInstallType_FILES)
+  , InstallMode(cmInstallMode::COPY)
   , Optional(false)
   , MessageAlways(false)
   , MessageLazy(false)
@@ -82,6 +89,93 @@ bool cmFileInstaller::Install(const std::string& fromFile,
   return this->cmFileCopier::Install(fromFile, toFile);
 }
 
+bool cmFileInstaller::InstallFile(const std::string& fromFile,
+                                  const std::string& toFile,
+                                  MatchProperties match_properties)
+{
+  if (this->InstallMode == cmInstallMode::COPY) {
+    return this->cmFileCopier::InstallFile(fromFile, toFile, match_properties);
+  }
+
+  std::string newFromFile;
+
+  if (this->InstallMode == cmInstallMode::REL_SYMLINK ||
+      this->InstallMode == cmInstallMode::REL_SYMLINK_OR_COPY ||
+      this->InstallMode == cmInstallMode::SYMLINK ||
+      this->InstallMode == cmInstallMode::SYMLINK_OR_COPY) {
+    // Try to get a relative path.
+    std::string toDir = cmSystemTools::GetParentDirectory(toFile);
+    newFromFile = cmSystemTools::ForceToRelativePath(toDir, fromFile);
+
+    // Double check that we can restore the original path.
+    std::string reassembled =
+      cmSystemTools::CollapseFullPath(newFromFile, toDir);
+    if (!cmSystemTools::ComparePath(reassembled, fromFile)) {
+      if (this->InstallMode == cmInstallMode::SYMLINK ||
+          this->InstallMode == cmInstallMode::SYMLINK_OR_COPY) {
+        // User does not mind, silently proceed with absolute path.
+        newFromFile = fromFile;
+      } else if (this->InstallMode == cmInstallMode::REL_SYMLINK_OR_COPY) {
+        // User expects a relative symbolic link or a copy.
+        // Since an absolute symlink won't do, copy instead.
+        return this->cmFileCopier::InstallFile(fromFile, toFile,
+                                               match_properties);
+      } else {
+        // We cannot meet user's expectation (REL_SYMLINK)
+        auto e = cmStrCat(this->Name,
+                          " cannot determine relative path for symlink to \"",
+                          newFromFile, "\" at \"", toFile, "\".");
+        this->Status.SetError(e);
+        return false;
+      }
+    }
+  } else {
+    newFromFile = fromFile; // stick with absolute path
+  }
+
+  // Compare the symlink value to that at the destination if not
+  // always installing.
+  bool copy = true;
+  if (!this->Always) {
+    std::string oldSymlinkTarget;
+    if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
+      if (newFromFile == oldSymlinkTarget) {
+        copy = false;
+      }
+    }
+  }
+
+  // Inform the user about this file installation.
+  this->ReportCopy(toFile, TypeLink, copy);
+
+  if (copy) {
+    // Remove the destination file so we can always create the symlink.
+    cmSystemTools::RemoveFile(toFile);
+
+    // Create destination directory if it doesn't exist
+    cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(toFile));
+
+    // Create the symlink.
+    if (!cmSystemTools::CreateSymlink(newFromFile, toFile)) {
+      if (this->InstallMode == cmInstallMode::ABS_SYMLINK_OR_COPY ||
+          this->InstallMode == cmInstallMode::REL_SYMLINK_OR_COPY ||
+          this->InstallMode == cmInstallMode::SYMLINK_OR_COPY) {
+        // Failed to create a symbolic link, fall back to copying.
+        return this->cmFileCopier::InstallFile(newFromFile, toFile,
+                                               match_properties);
+      }
+
+      auto e = cmStrCat(this->Name, " cannot create symlink to \"",
+                        newFromFile, "\" at \"", toFile,
+                        "\": ", cmSystemTools::GetLastSystemError(), "\".");
+      this->Status.SetError(e);
+      return false;
+    }
+  }
+
+  return true;
+}
+
 void cmFileInstaller::DefaultFilePermissions()
 {
   this->cmFileCopier::DefaultFilePermissions();
@@ -141,6 +235,31 @@ bool cmFileInstaller::Parse(std::vector<std::string> const& args)
     return false;
   }
 
+  static const std::map<cm::string_view, cmInstallMode> install_mode_dict{
+    { "ABS_SYMLINK"_s, cmInstallMode::ABS_SYMLINK },
+    { "ABS_SYMLINK_OR_COPY"_s, cmInstallMode::ABS_SYMLINK_OR_COPY },
+    { "REL_SYMLINK"_s, cmInstallMode::REL_SYMLINK },
+    { "REL_SYMLINK_OR_COPY"_s, cmInstallMode::REL_SYMLINK_OR_COPY },
+    { "SYMLINK"_s, cmInstallMode::SYMLINK },
+    { "SYMLINK_OR_COPY"_s, cmInstallMode::SYMLINK_OR_COPY }
+  };
+
+  std::string install_mode;
+  cmSystemTools::GetEnv("CMAKE_INSTALL_MODE", install_mode);
+  if (install_mode.empty() || install_mode == "COPY"_s) {
+    this->InstallMode = cmInstallMode::COPY;
+  } else {
+    auto it = install_mode_dict.find(install_mode);
+    if (it != install_mode_dict.end()) {
+      this->InstallMode = it->second;
+    } else {
+      auto e = cmStrCat("Unrecognized value '", install_mode,
+                        "' for environment variable CMAKE_INSTALL_MODE");
+      this->Status.SetError(e);
+      return false;
+    }
+  }
+
   return true;
 }
 
index 3a905d3..3f6bd45 100644 (file)
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "cmFileCopier.h"
+#include "cmInstallMode.h"
 #include "cmInstallType.h"
 
 class cmExecutionStatus;
@@ -19,6 +20,7 @@ struct cmFileInstaller : public cmFileCopier
 
 protected:
   cmInstallType InstallType;
+  cmInstallMode InstallMode;
   bool Optional;
   bool MessageAlways;
   bool MessageLazy;
@@ -35,7 +37,8 @@ protected:
   bool ReportMissing(const std::string& fromFile) override;
   bool Install(const std::string& fromFile,
                const std::string& toFile) override;
-
+  bool InstallFile(const std::string& fromFile, const std::string& toFile,
+                   MatchProperties match_properties) override;
   bool Parse(std::vector<std::string> const& args) override;
   enum
   {
index 1038ac2..a123e44 100644 (file)
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmSearchPath.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 class cmExecutionStatus;
@@ -301,9 +301,9 @@ void cmFindBase::FillUserGuessPath()
 
 bool cmFindBase::CheckForVariableDefined()
 {
-  if (cmProp value = this->Makefile->GetDefinition(this->VariableName)) {
+  if (cmValue value = this->Makefile->GetDefinition(this->VariableName)) {
     cmState* state = this->Makefile->GetState();
-    cmProp cacheEntry = state->GetCacheEntryValue(this->VariableName);
+    cmValue cacheEntry = state->GetCacheEntryValue(this->VariableName);
     bool found = !cmIsNOTFOUND(*value);
     bool cached = cacheEntry != nullptr;
     auto cacheType = cached ? state->GetCacheEntryType(this->VariableName)
@@ -311,7 +311,7 @@ bool cmFindBase::CheckForVariableDefined()
 
     if (cached && cacheType != cmStateEnums::UNINITIALIZED) {
       this->VariableType = cacheType;
-      if (const auto* hs =
+      if (const auto& hs =
             state->GetCacheEntryProperty(this->VariableName, "HELPSTRING")) {
         this->VariableDocumentation = *hs;
       }
@@ -336,7 +336,7 @@ void cmFindBase::NormalizeFindResult()
   if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0125) ==
       cmPolicies::NEW) {
     // ensure the path returned by find_* command is absolute
-    const auto* existingValue =
+    const auto& existingValue =
       this->Makefile->GetDefinition(this->VariableName);
     std::string value;
     if (!existingValue->empty()) {
@@ -358,8 +358,8 @@ void cmFindBase::NormalizeFindResult()
       // value.
       if (value != *existingValue || this->AlreadyInCacheWithoutMetaInfo) {
         this->Makefile->GetCMakeInstance()->AddCacheEntry(
-          this->VariableName, value.c_str(),
-          this->VariableDocumentation.c_str(), this->VariableType);
+          this->VariableName, value, this->VariableDocumentation.c_str(),
+          this->VariableType);
         if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0126) ==
             cmPolicies::NEW) {
           if (this->Makefile->IsNormalDefinitionSet(this->VariableName)) {
index d2f9619..bdc9207 100644 (file)
@@ -11,9 +11,9 @@
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 cmFindCommon::PathGroup cmFindCommon::PathGroup::All("ALL");
@@ -183,7 +183,7 @@ void cmFindCommon::SelectDefaultSearchModes()
   };
 
   for (auto const& path : search_paths) {
-    cmProp def = this->Makefile->GetDefinition(path.second);
+    cmValue def = this->Makefile->GetDefinition(path.second);
     if (def) {
       path.first = !cmIsOn(*def);
     }
@@ -203,11 +203,11 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths)
     return;
   }
 
-  cmProp sysroot = this->Makefile->GetDefinition("CMAKE_SYSROOT");
-  cmProp sysrootCompile =
+  cmValue sysroot = this->Makefile->GetDefinition("CMAKE_SYSROOT");
+  cmValue sysrootCompile =
     this->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE");
-  cmProp sysrootLink = this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK");
-  cmProp rootPath = this->Makefile->GetDefinition("CMAKE_FIND_ROOT_PATH");
+  cmValue sysrootLink = this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK");
+  cmValue rootPath = this->Makefile->GetDefinition("CMAKE_FIND_ROOT_PATH");
   const bool noSysroot = !cmNonempty(sysroot);
   const bool noCompileSysroot = !cmNonempty(sysrootCompile);
   const bool noLinkSysroot = !cmNonempty(sysrootLink);
@@ -234,7 +234,7 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths)
     cmSystemTools::ConvertToUnixSlashes(r);
   }
 
-  cmProp stagePrefix = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
+  cmValue stagePrefix = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
 
   // Copy the original set of unrooted paths.
   std::vector<std::string> unrootedPaths = paths;
index 0cbe637..ff04bab 100644 (file)
 
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 class cmExecutionStatus;
 
@@ -46,7 +46,7 @@ bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn)
 
   // add custom lib<qual> paths instead of using fixed lib32, lib64 or
   // libx32
-  if (cmProp customLib = this->Makefile->GetDefinition(
+  if (cmValue customLib = this->Makefile->GetDefinition(
         "CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX")) {
     this->AddArchitecturePaths(customLib->c_str());
   }
@@ -247,7 +247,7 @@ struct cmFindLibraryHelper
         cmStrCat(this->PrefixRegexStr, name, this->SuffixRegexStr);
       this->DebugSearches.FailedAt(path, regexName);
     }
-  };
+  }
 
   void DebugLibraryFound(std::string const& name, std::string const& path)
   {
@@ -256,9 +256,37 @@ struct cmFindLibraryHelper
         cmStrCat(this->PrefixRegexStr, name, this->SuffixRegexStr);
       this->DebugSearches.FoundAt(path, regexName);
     }
-  };
+  }
 };
 
+namespace {
+
+std::string const& get_prefixes(cmMakefile* mf)
+{
+#ifdef _WIN32
+  static std::string defaultPrefix = ";lib";
+#else
+  static std::string defaultPrefix = "lib";
+#endif
+  cmValue prefixProp = mf->GetDefinition("CMAKE_FIND_LIBRARY_PREFIXES");
+  return (prefixProp) ? *prefixProp : defaultPrefix;
+}
+
+std::string const& get_suffixes(cmMakefile* mf)
+{
+#ifdef _WIN32
+  static std::string defaultSuffix = ".lib;.dll.a;.a";
+#elif defined(__APPLE__)
+  static std::string defaultSuffix = ".tbd;.dylib;.so;.a";
+#elif defined(__hpux)
+  static std::string defaultSuffix = ".sl;.so;.a";
+#else
+  static std::string defaultSuffix = ".so;.a";
+#endif
+  cmValue suffixProp = mf->GetDefinition("CMAKE_FIND_LIBRARY_SUFFIXES");
+  return (suffixProp) ? *suffixProp : defaultSuffix;
+}
+}
 cmFindLibraryHelper::cmFindLibraryHelper(std::string debugName, cmMakefile* mf,
                                          cmFindBase const* base)
   : Makefile(mf)
@@ -268,10 +296,9 @@ cmFindLibraryHelper::cmFindLibraryHelper(std::string debugName, cmMakefile* mf,
   this->GG = this->Makefile->GetGlobalGenerator();
 
   // Collect the list of library name prefixes/suffixes to try.
-  std::string const& prefixes_list =
-    this->Makefile->GetRequiredDefinition("CMAKE_FIND_LIBRARY_PREFIXES");
-  std::string const& suffixes_list =
-    this->Makefile->GetRequiredDefinition("CMAKE_FIND_LIBRARY_SUFFIXES");
+  std::string const& prefixes_list = get_prefixes(this->Makefile);
+  std::string const& suffixes_list = get_suffixes(this->Makefile);
+
   cmExpandList(prefixes_list, this->Prefixes, true);
   cmExpandList(suffixes_list, this->Suffixes, true);
   this->RegexFromList(this->PrefixRegexStr, this->Prefixes);
index fba736e..335ebbe 100644 (file)
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmSearchPath.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 
 #if defined(__HAIKU__)
@@ -137,7 +137,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
   }
 
   // Lookup required version of CMake.
-  if (cmProp rv =
+  if (cmValue rv =
         this->Makefile->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
     unsigned int v[3] = { 0, 0, 0 };
     sscanf(rv->c_str(), "%u.%u.%u", &v[0], &v[1], &v[2]);
@@ -148,7 +148,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
   this->DebugBuffer.clear();
 
   // Lookup target architecture, if any.
-  if (cmProp arch =
+  if (cmValue arch =
         this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) {
     this->LibraryArchitecture = *arch;
   }
@@ -177,7 +177,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
   // Check if User Package Registry should be disabled
   // The `CMAKE_FIND_USE_PACKAGE_REGISTRY` has
   // priority over the deprecated CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY
-  if (cmProp def =
+  if (cmValue def =
         this->Makefile->GetDefinition("CMAKE_FIND_USE_PACKAGE_REGISTRY")) {
     this->NoUserRegistry = !cmIsOn(*def);
   } else if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY")) {
@@ -187,7 +187,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
   // Check if System Package Registry should be disabled
   // The `CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY` has
   // priority over the deprecated CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY
-  if (cmProp def = this->Makefile->GetDefinition(
+  if (cmValue def = this->Makefile->GetDefinition(
         "CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY")) {
     this->NoSystemRegistry = !cmIsOn(*def);
   } else if (this->Makefile->IsOn(
@@ -201,7 +201,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
   }
 
   // Check if Sorting should be enabled
-  if (cmProp so =
+  if (cmValue so =
         this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_ORDER")) {
 
     if (*so == "NAME") {
@@ -212,7 +212,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
       this->SortOrder = None;
     }
   }
-  if (cmProp sd =
+  if (cmValue sd =
         this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_DIRECTION")) {
     this->SortDirection = (*sd == "ASC") ? Asc : Dec;
   }
@@ -478,17 +478,35 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
       this->VersionMaxPatch, this->VersionMaxTweak);
   }
 
+  const std::string makePackageRequiredVar =
+    cmStrCat("CMAKE_REQUIRE_FIND_PACKAGE_", this->Name);
+  const bool makePackageRequiredSet =
+    this->Makefile->IsOn(makePackageRequiredVar);
+  if (makePackageRequiredSet) {
+    if (this->Required) {
+      this->Makefile->IssueMessage(
+        MessageType::WARNING,
+        cmStrCat("for module ", this->Name,
+                 " already called with REQUIRED, thus ",
+                 makePackageRequiredVar, " has no effect."));
+    } else {
+      this->Required = true;
+    }
+  }
+
   std::string disableFindPackageVar =
     cmStrCat("CMAKE_DISABLE_FIND_PACKAGE_", this->Name);
   if (this->Makefile->IsOn(disableFindPackageVar)) {
     if (this->Required) {
       this->SetError(
-        cmStrCat("for module ", this->Name, " called with REQUIRED, but ",
-                 disableFindPackageVar,
+        cmStrCat("for module ", this->Name,
+                 (makePackageRequiredSet
+                    ? " was made REQUIRED with " + makePackageRequiredVar
+                    : " called with REQUIRED, "),
+                 " but ", disableFindPackageVar,
                  " is enabled. A REQUIRED package cannot be disabled."));
       return false;
     }
-
     return true;
   }
 
@@ -735,7 +753,7 @@ void cmFindPackageCommand::SetModuleVariables(const std::string& components)
 void cmFindPackageCommand::AddFindDefinition(const std::string& var,
                                              cm::string_view value)
 {
-  if (cmProp old = this->Makefile->GetDefinition(var)) {
+  if (cmValue old = this->Makefile->GetDefinition(var)) {
     this->OriginalDefs[var].exists = true;
     this->OriginalDefs[var].value = *old;
   } else {
@@ -828,7 +846,7 @@ bool cmFindPackageCommand::HandlePackageMode(
   this->ConsideredConfigs.clear();
 
   // Try to find the config file.
-  cmProp def = this->Makefile->GetDefinition(this->Variable);
+  cmValue def = this->Makefile->GetDefinition(this->Variable);
 
   // Try to load the config file if the directory is known
   bool fileFound = false;
@@ -1188,7 +1206,7 @@ bool cmFindPackageCommand::ReadListFile(const std::string& f,
 void cmFindPackageCommand::AppendToFoundProperty(bool found)
 {
   std::vector<std::string> foundContents;
-  cmProp foundProp =
+  cmValue foundProp =
     this->Makefile->GetState()->GetGlobalProperty("PACKAGES_FOUND");
   if (cmNonempty(foundProp)) {
     cmExpandList(*foundProp, foundContents, false);
@@ -1200,7 +1218,7 @@ void cmFindPackageCommand::AppendToFoundProperty(bool found)
   }
 
   std::vector<std::string> notFoundContents;
-  cmProp notFoundProp =
+  cmValue notFoundProp =
     this->Makefile->GetState()->GetGlobalProperty("PACKAGES_NOT_FOUND");
   if (cmNonempty(notFoundProp)) {
     cmExpandList(*notFoundProp, notFoundContents, false);
index 4845a6d..dcb3626 100644 (file)
@@ -30,6 +30,7 @@
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 namespace {
 class cmForEachFunctionBlocker : public cmFunctionBlocker
index 1b14d17..70fe537 100644 (file)
@@ -40,6 +40,8 @@ int cmFortranParser_GetOldStartcond(cmFortranParser* parser);
 /* Callbacks for parser.  */
 void cmFortranParser_Error(cmFortranParser* parser, const char* message);
 void cmFortranParser_RuleUse(cmFortranParser* parser, const char* module_name);
+void cmFortranParser_RuleUseIntrinsic(cmFortranParser* parser,
+                                      const char* module_name);
 void cmFortranParser_RuleLineDirective(cmFortranParser* parser,
                                        const char* filename);
 void cmFortranParser_RuleInclude(cmFortranParser* parser, const char* name);
@@ -99,6 +101,9 @@ public:
   std::set<std::string> Provides;
   std::set<std::string> Requires;
 
+  // Set of intrinsic modules.
+  std::set<std::string> Intrinsics;
+
   // Set of files included in the translation unit.
   std::set<std::string> Includes;
 };
index 054a2a9..efcc5bb 100644 (file)
@@ -197,6 +197,19 @@ void cmFortranParser_RuleUse(cmFortranParser* parser, const char* module_name)
   parser->Info.Requires.insert(parser->ModName(mod_name));
 }
 
+void cmFortranParser_RuleUseIntrinsic(cmFortranParser* parser,
+                                      const char* module_name)
+{
+  if (parser->InPPFalseBranch) {
+    return;
+  }
+
+  // syntax:   "use, intrinsic:: module_name"
+  // requires: "module_name.mod"
+  std::string const& mod_name = cmSystemTools::LowerCase(module_name);
+  parser->Info.Intrinsics.insert(parser->ModName(mod_name));
+}
+
 void cmFortranParser_RuleLineDirective(cmFortranParser* parser,
                                        const char* filename)
 {
index 217ebe5..c357ee1 100644 (file)
@@ -37,7 +37,6 @@
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmStandardLevelResolver.h"
 #include "cmState.h"
@@ -46,6 +45,7 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 std::string cmGeneratorExpressionNode::EvaluateDependentExpression(
@@ -771,8 +771,7 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode
     }
 
     return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
-                                         parameters.front().c_str(),
-                                         compilerVersion.c_str())
+                                         parameters.front(), compilerVersion)
       ? "1"
       : "0";
   }
@@ -830,8 +829,7 @@ struct VersionNode : public cmGeneratorExpressionNode
     const GeneratorExpressionContent* /*content*/,
     cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
   {
-    return cmSystemTools::VersionCompare(Op, parameters.front().c_str(),
-                                         parameters[1].c_str())
+    return cmSystemTools::VersionCompare(Op, parameters.front(), parameters[1])
       ? "1"
       : "0";
   }
@@ -916,8 +914,8 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
     }
 
     if (context->CurrentTarget && context->CurrentTarget->IsImported()) {
-      cmProp loc = nullptr;
-      cmProp imp = nullptr;
+      cmValue loc = nullptr;
+      cmValue imp = nullptr;
       std::string suffix;
       if (context->CurrentTarget->Target->GetMappedConfig(context->Config, loc,
                                                           imp, suffix)) {
@@ -927,7 +925,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
         std::vector<std::string> mappedConfigs;
         std::string mapProp = cmStrCat(
           "MAP_IMPORTED_CONFIG_", cmSystemTools::UpperCase(context->Config));
-        if (cmProp mapValue = context->CurrentTarget->GetProperty(mapProp)) {
+        if (cmValue mapValue = context->CurrentTarget->GetProperty(mapProp)) {
           cmExpandList(cmSystemTools::UpperCase(*mapValue), mappedConfigs);
 
           for (auto const& param : parameters) {
@@ -1504,7 +1502,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
 
     std::string result;
     bool haveProp = false;
-    if (cmProp p = target->GetProperty(propertyName)) {
+    if (cmValue p = target->GetProperty(propertyName)) {
       result = *p;
       haveProp = true;
     } else if (evaluatingLinkLibraries) {
@@ -1654,8 +1652,8 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
     std::vector<std::string> objects;
 
     if (gt->IsImported()) {
-      cmProp loc = nullptr;
-      cmProp imp = nullptr;
+      cmValue loc = nullptr;
+      cmValue imp = nullptr;
       std::string suffix;
       if (gt->Target->GetMappedConfig(context->Config, loc, imp, suffix)) {
         cmExpandList(*loc, objects);
@@ -1777,7 +1775,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
       testedFeatures[lang].push_back(p);
 
       if (availableFeatures.find(lang) == availableFeatures.end()) {
-        const char* featuresKnown =
+        cmValue featuresKnown =
           standardResolver.CompileFeaturesAvailable(lang, &error);
         if (!featuresKnown) {
           reportError(context, content->GetOriginalExpression(), error);
@@ -1792,7 +1790,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
     for (auto const& lit : testedFeatures) {
       std::vector<std::string> const& langAvailable =
         availableFeatures[lit.first];
-      cmProp standardDefault = context->LG->GetMakefile()->GetDefinition(
+      cmValue standardDefault = context->LG->GetMakefile()->GetDefinition(
         "CMAKE_" + lit.first + "_STANDARD_DEFAULT");
       for (std::string const& it : lit.second) {
         if (!cm::contains(langAvailable, it)) {
@@ -1806,7 +1804,8 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
         if (!standardResolver.HaveStandardAvailable(target, lit.first,
                                                     context->Config, it)) {
           if (evalLL) {
-            cmProp l = target->GetLanguageStandard(lit.first, context->Config);
+            cmValue l =
+              target->GetLanguageStandard(lit.first, context->Config);
             if (!l) {
               l = standardDefault;
             }
index f1ef130..8033ef5 100644 (file)
@@ -58,11 +58,11 @@ const cmsys::RegularExpression FrameworkRegularExpression(
 }
 
 template <>
-cmProp cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
+cmValue cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
   cmGeneratorTarget const* tgt, cmMessenger* /* messenger */,
   cmListFileBacktrace const& /* context */)
 {
-  return &tgt->GetSourcesProperty();
+  return tgt->GetSourcesProperty();
 }
 
 template <>
@@ -145,12 +145,10 @@ private:
 class TargetPropertyEntryString : public cmGeneratorTarget::TargetPropertyEntry
 {
 public:
-  TargetPropertyEntryString(std::string propertyValue,
-                            cmListFileBacktrace backtrace,
+  TargetPropertyEntryString(BT<std::string> propertyValue,
                             cmLinkImplItem const& item = NoLinkImplItem)
     : cmGeneratorTarget::TargetPropertyEntry(item)
     , PropertyValue(std::move(propertyValue))
-    , Backtrace(std::move(backtrace))
   {
   }
 
@@ -159,46 +157,46 @@ public:
                               cmGeneratorExpressionDAGChecker*,
                               std::string const&) const override
   {
-    return this->PropertyValue;
+    return this->PropertyValue.Value;
   }
 
-  cmListFileBacktrace GetBacktrace() const override { return this->Backtrace; }
-  std::string const& GetInput() const override { return this->PropertyValue; }
+  cmListFileBacktrace GetBacktrace() const override
+  {
+    return this->PropertyValue.Backtrace;
+  }
+  std::string const& GetInput() const override
+  {
+    return this->PropertyValue.Value;
+  }
 
 private:
-  std::string PropertyValue;
-  cmListFileBacktrace Backtrace;
+  BT<std::string> PropertyValue;
 };
 
 std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>
-CreateTargetPropertyEntry(
-  const std::string& propertyValue,
-  cmListFileBacktrace backtrace = cmListFileBacktrace(),
-  bool evaluateForBuildsystem = false)
+CreateTargetPropertyEntry(const BT<std::string>& propertyValue,
+                          bool evaluateForBuildsystem = false)
 {
-  if (cmGeneratorExpression::Find(propertyValue) != std::string::npos) {
-    cmGeneratorExpression ge(std::move(backtrace));
+  if (cmGeneratorExpression::Find(propertyValue.Value) != std::string::npos) {
+    cmGeneratorExpression ge(propertyValue.Backtrace);
     std::unique_ptr<cmCompiledGeneratorExpression> cge =
-      ge.Parse(propertyValue);
+      ge.Parse(propertyValue.Value);
     cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
     return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>(
       cm::make_unique<TargetPropertyEntryGenex>(std::move(cge)));
   }
 
   return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>(
-    cm::make_unique<TargetPropertyEntryString>(propertyValue,
-                                               std::move(backtrace)));
+    cm::make_unique<TargetPropertyEntryString>(propertyValue));
 }
 
 void CreatePropertyGeneratorExpressions(
-  cmStringRange entries, cmBacktraceRange backtraces,
+  cmBTStringRange entries,
   std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>>& items,
   bool evaluateForBuildsystem = false)
 {
-  auto btIt = backtraces.begin();
-  for (auto it = entries.begin(); it != entries.end(); ++it, ++btIt) {
-    items.push_back(
-      CreateTargetPropertyEntry(*it, *btIt, evaluateForBuildsystem));
+  for (auto const& entry : entries) {
+    items.push_back(CreateTargetPropertyEntry(entry, evaluateForBuildsystem));
   }
 }
 
@@ -289,35 +287,27 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
   this->GlobalGenerator->ComputeTargetObjectDirectory(this);
 
   CreatePropertyGeneratorExpressions(t->GetIncludeDirectoriesEntries(),
-                                     t->GetIncludeDirectoriesBacktraces(),
                                      this->IncludeDirectoriesEntries);
 
   CreatePropertyGeneratorExpressions(t->GetCompileOptionsEntries(),
-                                     t->GetCompileOptionsBacktraces(),
                                      this->CompileOptionsEntries);
 
   CreatePropertyGeneratorExpressions(t->GetCompileFeaturesEntries(),
-                                     t->GetCompileFeaturesBacktraces(),
                                      this->CompileFeaturesEntries);
 
   CreatePropertyGeneratorExpressions(t->GetCompileDefinitionsEntries(),
-                                     t->GetCompileDefinitionsBacktraces(),
                                      this->CompileDefinitionsEntries);
 
   CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(),
-                                     t->GetLinkOptionsBacktraces(),
                                      this->LinkOptionsEntries);
 
   CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(),
-                                     t->GetLinkDirectoriesBacktraces(),
                                      this->LinkDirectoriesEntries);
 
   CreatePropertyGeneratorExpressions(t->GetPrecompileHeadersEntries(),
-                                     t->GetPrecompileHeadersBacktraces(),
                                      this->PrecompileHeadersEntries);
 
   CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
-                                     t->GetSourceBacktraces(),
                                      this->SourceEntries, true);
 
   this->PolicyMap = t->GetPolicyMap();
@@ -332,7 +322,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
 
 cmGeneratorTarget::~cmGeneratorTarget() = default;
 
-const std::string& cmGeneratorTarget::GetSourcesProperty() const
+cmValue cmGeneratorTarget::GetSourcesProperty() const
 {
   std::vector<std::string> values;
   for (auto const& se : this->SourceEntries) {
@@ -341,7 +331,7 @@ const std::string& cmGeneratorTarget::GetSourcesProperty() const
   static std::string value;
   value.clear();
   value = cmJoin(values, ";");
-  return value;
+  return cmValue(value);
 }
 
 cmGlobalGenerator* cmGeneratorTarget::GetGlobalGenerator() const
@@ -366,7 +356,7 @@ const std::string& cmGeneratorTarget::GetName() const
 
 std::string cmGeneratorTarget::GetExportName() const
 {
-  cmProp exportName = this->GetProperty("EXPORT_NAME");
+  cmValue exportName = this->GetProperty("EXPORT_NAME");
 
   if (cmNonempty(exportName)) {
     if (!cmGeneratorExpression::IsValidTargetName(*exportName)) {
@@ -381,9 +371,9 @@ std::string cmGeneratorTarget::GetExportName() const
   return this->GetName();
 }
 
-cmProp cmGeneratorTarget::GetProperty(const std::string& prop) const
+cmValue cmGeneratorTarget::GetProperty(const std::string& prop) const
 {
-  if (cmProp result = cmTargetPropertyComputer::GetProperty(
+  if (cmValue result = cmTargetPropertyComputer::GetProperty(
         this, prop, this->Makefile->GetMessenger(), this->GetBacktrace())) {
     return result;
   }
@@ -396,13 +386,7 @@ cmProp cmGeneratorTarget::GetProperty(const std::string& prop) const
 std::string const& cmGeneratorTarget::GetSafeProperty(
   std::string const& prop) const
 {
-  cmProp ret = this->GetProperty(prop);
-  if (ret) {
-    return *ret;
-  }
-
-  static std::string const s_empty;
-  return s_empty;
+  return this->GetProperty(prop);
 }
 
 const char* cmGeneratorTarget::GetOutputTargetType(
@@ -491,7 +475,7 @@ std::string cmGeneratorTarget::GetOutputName(
 
     std::string outName;
     for (std::string const& p : props) {
-      if (cmProp outNameProp = this->GetProperty(p)) {
+      if (cmValue outNameProp = this->GetProperty(p)) {
         outName = *outNameProp;
         break;
       }
@@ -519,7 +503,7 @@ std::string cmGeneratorTarget::GetFilePrefix(
   const std::string& config, cmStateEnums::ArtifactType artifact) const
 {
   if (this->IsImported()) {
-    cmProp prefix = this->GetFilePrefixInternal(config, artifact);
+    cmValue prefix = this->GetFilePrefixInternal(config, artifact);
     return prefix ? *prefix : std::string();
   }
 
@@ -533,7 +517,7 @@ std::string cmGeneratorTarget::GetFileSuffix(
   const std::string& config, cmStateEnums::ArtifactType artifact) const
 {
   if (this->IsImported()) {
-    cmProp suffix = this->GetFileSuffixInternal(config, artifact);
+    cmValue suffix = this->GetFileSuffixInternal(config, artifact);
     return suffix ? *suffix : std::string();
   }
 
@@ -546,7 +530,7 @@ std::string cmGeneratorTarget::GetFileSuffix(
 
 std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
 {
-  cmProp postfix = nullptr;
+  cmValue postfix = nullptr;
   std::string frameworkPostfix;
   if (!config.empty()) {
     std::string configProp =
@@ -564,7 +548,7 @@ std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
     // framework postfix.
     frameworkPostfix = this->GetFrameworkMultiConfigPostfix(config);
     if (!frameworkPostfix.empty()) {
-      postfix = &frameworkPostfix;
+      postfix = cmValue(frameworkPostfix);
     }
   }
   return postfix ? *postfix : std::string();
@@ -573,7 +557,7 @@ std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
 std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix(
   const std::string& config) const
 {
-  cmProp postfix = nullptr;
+  cmValue postfix = nullptr;
   if (!config.empty()) {
     std::string configProp = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_",
                                       cmSystemTools::UpperCase(config));
@@ -588,7 +572,7 @@ std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix(
   return postfix ? *postfix : std::string();
 }
 
-cmProp cmGeneratorTarget::GetFilePrefixInternal(
+cmValue cmGeneratorTarget::GetFilePrefixInternal(
   std::string const& config, cmStateEnums::ArtifactType artifact,
   const std::string& language) const
 {
@@ -618,7 +602,7 @@ cmProp cmGeneratorTarget::GetFilePrefixInternal(
   }
 
   // Compute prefix value.
-  cmProp targetPrefix =
+  cmValue targetPrefix =
     (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
                                : this->GetProperty("PREFIX"));
 
@@ -639,7 +623,7 @@ cmProp cmGeneratorTarget::GetFilePrefixInternal(
   return targetPrefix;
 }
 
-cmProp cmGeneratorTarget::GetFileSuffixInternal(
+cmValue cmGeneratorTarget::GetFileSuffixInternal(
   std::string const& config, cmStateEnums::ArtifactType artifact,
   const std::string& language) const
 {
@@ -669,7 +653,7 @@ cmProp cmGeneratorTarget::GetFileSuffixInternal(
   }
 
   // Compute suffix value.
-  cmProp targetSuffix =
+  cmValue targetSuffix =
     (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
                                : this->GetProperty("SUFFIX"));
 
@@ -704,7 +688,8 @@ void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before)
 {
   this->SourceEntries.insert(
     before ? this->SourceEntries.begin() : this->SourceEntries.end(),
-    CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
+    CreateTargetPropertyEntry(
+      BT<std::string>(src, this->Makefile->GetBacktrace()), true));
   this->ClearSourcesCache();
 }
 
@@ -725,11 +710,13 @@ void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs)
 void cmGeneratorTarget::AddIncludeDirectory(const std::string& src,
                                             bool before)
 {
-  this->Target->InsertInclude(src, this->Makefile->GetBacktrace(), before);
+  this->Target->InsertInclude(
+    BT<std::string>(src, this->Makefile->GetBacktrace()), before);
   this->IncludeDirectoriesEntries.insert(
     before ? this->IncludeDirectoriesEntries.begin()
            : this->IncludeDirectoriesEntries.end(),
-    CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
+    CreateTargetPropertyEntry(
+      BT<std::string>(src, this->Makefile->GetBacktrace()), true));
 }
 
 std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
@@ -751,7 +738,7 @@ void handleSystemIncludesDep(cmLocalGenerator* lg,
                              std::vector<std::string>& result,
                              bool excludeImported, std::string const& language)
 {
-  if (cmProp dirs =
+  if (cmValue dirs =
         depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) {
     cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget,
                                                  dagChecker, depTgt, language),
@@ -761,7 +748,7 @@ void handleSystemIncludesDep(cmLocalGenerator* lg,
     return;
   }
 
-  if (cmProp dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
+  if (cmValue dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
     cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget,
                                                  dagChecker, depTgt, language),
                  result);
@@ -813,17 +800,17 @@ void cmGeneratorTarget::ComputeObjectMapping()
   }
 }
 
-cmProp cmGeneratorTarget::GetFeature(const std::string& feature,
-                                     const std::string& config) const
+cmValue cmGeneratorTarget::GetFeature(const std::string& feature,
+                                      const std::string& config) const
 {
   if (!config.empty()) {
     std::string featureConfig =
       cmStrCat(feature, '_', cmSystemTools::UpperCase(config));
-    if (cmProp value = this->GetProperty(featureConfig)) {
+    if (cmValue value = this->GetProperty(featureConfig)) {
       return value;
     }
   }
-  if (cmProp value = this->GetProperty(feature)) {
+  if (cmValue value = this->GetProperty(feature)) {
     return value;
   }
   return this->LocalGenerator->GetFeature(feature, config);
@@ -851,7 +838,7 @@ const char* cmGeneratorTarget::GetLinkPIEProperty(
 bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang,
                                      std::string const& config) const
 {
-  cmProp feature = this->GetFeature("INTERPROCEDURAL_OPTIMIZATION", config);
+  cmValue feature = this->GetFeature("INTERPROCEDURAL_OPTIMIZATION", config);
 
   if (!cmIsOn(feature)) {
     // 'INTERPROCEDURAL_OPTIMIZATION' is off, no need to check policies
@@ -959,23 +946,23 @@ BTs<std::string> const* cmGeneratorTarget::GetLanguageStandardProperty(
     cmStrCat(lang, "_STANDARD"));
 }
 
-cmProp cmGeneratorTarget::GetLanguageStandard(std::string const& lang,
-                                              std::string const& config) const
+cmValue cmGeneratorTarget::GetLanguageStandard(std::string const& lang,
+                                               std::string const& config) const
 {
   BTs<std::string> const* languageStandard =
     this->GetLanguageStandardProperty(lang, config);
 
   if (languageStandard) {
-    return &(languageStandard->Value);
+    return cmValue(languageStandard->Value);
   }
 
   return nullptr;
 }
 
-cmProp cmGeneratorTarget::GetPropertyWithPairedLanguageSupport(
+cmValue cmGeneratorTarget::GetPropertyWithPairedLanguageSupport(
   std::string const& lang, const char* suffix) const
 {
-  cmProp propertyValue = this->Target->GetProperty(cmStrCat(lang, suffix));
+  cmValue propertyValue = this->Target->GetProperty(cmStrCat(lang, suffix));
   if (!propertyValue) {
     // Check if we should use the value set by another language.
     if (lang == "OBJC") {
@@ -988,7 +975,7 @@ cmProp cmGeneratorTarget::GetPropertyWithPairedLanguageSupport(
   return propertyValue;
 }
 
-cmProp cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const
+cmValue cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const
 {
   return this->GetPropertyWithPairedLanguageSupport(lang, "_EXTENSIONS");
 }
@@ -1150,6 +1137,7 @@ bool cmGeneratorTarget::IsInBuildSystem() const
       if (!this->SourceEntries.empty()) {
         return true;
       }
+      break;
     case cmStateEnums::UNKNOWN_LIBRARY:
       break;
   }
@@ -1183,7 +1171,7 @@ const std::string& cmGeneratorTarget::GetLocationForBuild() const
   // Now handle the deprecated build-time configuration location.
   std::string const noConfig;
   location = this->GetDirectory(noConfig);
-  cmProp cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR");
+  cmValue cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR");
   if (cfgid && (*cfgid != ".")) {
     location += "/";
     location += *cfgid;
@@ -1343,7 +1331,7 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
   cmGeneratorTarget const* headTarget =
     context->HeadTarget ? context->HeadTarget : this;
 
-  if (cmProp p = this->GetProperty(prop)) {
+  if (cmValue p = this->GetProperty(prop)) {
     result = cmGeneratorExpressionNode::EvaluateDependentExpression(
       *p, context->LG, context, headTarget, &dagChecker, this);
   }
@@ -1466,7 +1454,7 @@ void AddLangSpecificImplicitIncludeDirectories(
           auto* lg = dependency->GetLocalGenerator();
           EvaluatedTargetPropertyEntry entry{ library, library.Backtrace };
 
-          if (cmProp val = dependency->GetProperty(propertyName)) {
+          if (cmValue val = dependency->GetProperty(propertyName)) {
             entry.Values.emplace_back(*val);
           } else {
             if (mode == IncludeDirectoryFallBack::BINARY) {
@@ -1681,9 +1669,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths(
     // for TARGET_OBJECTS instead for backwards compatibility with OLD
     // behavior of CMP0024 and CMP0026 only.
 
-    cmStringRange sourceEntries = this->Target->GetSourceEntries();
-    for (std::string const& entry : sourceEntries) {
-      std::vector<std::string> items = cmExpandedList(entry);
+    cmBTStringRange sourceEntries = this->Target->GetSourceEntries();
+    for (auto const& entry : sourceEntries) {
+      std::vector<std::string> items = cmExpandedList(entry.Value);
       for (std::string const& item : items) {
         if (cmHasLiteralPrefix(item, "$<TARGET_OBJECTS:") &&
             item.back() == '>') {
@@ -1998,12 +1986,12 @@ std::string cmGeneratorTarget::GetCompilePDBName(
   // Check for a per-configuration output directory target property.
   std::string configUpper = cmSystemTools::UpperCase(config);
   std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper);
-  cmProp config_name = this->GetProperty(configProp);
+  cmValue config_name = this->GetProperty(configProp);
   if (cmNonempty(config_name)) {
     return prefix + *config_name + ".pdb";
   }
 
-  cmProp name = this->GetProperty("COMPILE_PDB_NAME");
+  cmValue name = this->GetProperty("COMPILE_PDB_NAME");
   if (cmNonempty(name)) {
     return prefix + *name + ".pdb";
   }
@@ -2142,34 +2130,29 @@ bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const
     return true;
   }
 
-#if defined(CMake_USE_ELF_PARSER) || defined(CMake_USE_XCOFF_PARSER)
   // Enable if the rpath flag uses a separator and the target uses
   // binaries we know how to edit.
   std::string ll = this->GetLinkerLanguage(config);
   if (!ll.empty()) {
     std::string sepVar =
       cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG_SEP");
-    cmProp sep = this->Makefile->GetDefinition(sepVar);
+    cmValue sep = this->Makefile->GetDefinition(sepVar);
     if (cmNonempty(sep)) {
       // TODO: Add binary format check to ABI detection and get rid of
       // CMAKE_EXECUTABLE_FORMAT.
-      if (cmProp fmt =
+      if (cmValue fmt =
             this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) {
-#  if defined(CMake_USE_ELF_PARSER)
         if (*fmt == "ELF") {
           return true;
         }
-#  endif
-#  if defined(CMake_USE_XCOFF_PARSER)
+#if defined(CMake_USE_XCOFF_PARSER)
         if (*fmt == "XCOFF") {
           return true;
         }
-#  endif
+#endif
       }
     }
   }
-#endif
-  static_cast<void>(config);
   return false;
 }
 
@@ -2188,6 +2171,21 @@ bool cmGeneratorTarget::IsImportedSharedLibWithoutSOName(
 bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir(
   const std::string& config) const
 {
+  TargetPtrToBoolMap& cache = this->MacOSXRpathInstallNameDirCache[config];
+  const auto lookup = cache.find(this->Target);
+
+  if (lookup != cache.cend()) {
+    return lookup->second;
+  }
+
+  const bool result = this->DetermineHasMacOSXRpathInstallNameDir(config);
+  cache[this->Target] = result;
+  return result;
+}
+
+bool cmGeneratorTarget::DetermineHasMacOSXRpathInstallNameDir(
+  const std::string& config) const
+{
   bool install_name_is_rpath = false;
   bool macosx_rpath = false;
 
@@ -2195,7 +2193,7 @@ bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir(
     if (this->GetType() != cmStateEnums::SHARED_LIBRARY) {
       return false;
     }
-    cmProp install_name = this->GetProperty("INSTALL_NAME_DIR");
+    cmValue install_name = this->GetProperty("INSTALL_NAME_DIR");
     bool use_install_name = this->MacOSXUseInstallNameDir();
     if (install_name && use_install_name && *install_name == "@rpath") {
       install_name_is_rpath = true;
@@ -2253,7 +2251,7 @@ bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const
     return false;
   }
 
-  cmProp macosx_rpath_str = this->GetProperty("MACOSX_RPATH");
+  cmValue macosx_rpath_str = this->GetProperty("MACOSX_RPATH");
   if (macosx_rpath_str) {
     return this->GetPropertyAsBool("MACOSX_RPATH");
   }
@@ -2270,7 +2268,7 @@ bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const
 
 bool cmGeneratorTarget::MacOSXUseInstallNameDir() const
 {
-  cmProp build_with_install_name =
+  cmValue build_with_install_name =
     this->GetProperty("BUILD_WITH_INSTALL_NAME_DIR");
   if (build_with_install_name) {
     return cmIsOn(*build_with_install_name);
@@ -2363,7 +2361,7 @@ std::string cmGeneratorTarget::GetAppBundleDirectory(
 {
   std::string fpath = cmStrCat(
     this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
-  cmProp ext = this->GetProperty("BUNDLE_EXTENSION");
+  cmValue ext = this->GetProperty("BUNDLE_EXTENSION");
   fpath += (ext ? *ext : "app");
   if (shouldAddContentLevel(level) &&
       !this->Makefile->PlatformIsAppleEmbedded()) {
@@ -2393,7 +2391,7 @@ std::string cmGeneratorTarget::GetCFBundleDirectory(
   std::string fpath = cmStrCat(
     this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
   std::string ext;
-  if (cmProp p = this->GetProperty("BUNDLE_EXTENSION")) {
+  if (cmValue p = this->GetProperty("BUNDLE_EXTENSION")) {
     ext = *p;
   } else {
     if (this->IsXCTestOnApple()) {
@@ -2418,7 +2416,7 @@ std::string cmGeneratorTarget::GetFrameworkDirectory(
 {
   std::string fpath = cmStrCat(
     this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.');
-  cmProp ext = this->GetProperty("BUNDLE_EXTENSION");
+  cmValue ext = this->GetProperty("BUNDLE_EXTENSION");
   fpath += (ext ? *ext : "framework");
   if (shouldAddFullLevel(level) &&
       !this->Makefile->PlatformIsAppleEmbedded()) {
@@ -2470,7 +2468,7 @@ std::string cmGeneratorTarget::GetInstallNameDirForInstallTree(
 {
   if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
     std::string dir;
-    cmProp install_name_dir = this->GetProperty("INSTALL_NAME_DIR");
+    cmValue install_name_dir = this->GetProperty("INSTALL_NAME_DIR");
 
     if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) {
       if (cmNonempty(install_name_dir)) {
@@ -2519,7 +2517,7 @@ const std::string* cmGeneratorTarget::GetExportMacro() const
   if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
       this->GetType() == cmStateEnums::MODULE_LIBRARY ||
       this->IsExecutableWithExports()) {
-    if (cmProp custom_export_name = this->GetProperty("DEFINE_SYMBOL")) {
+    if (cmValue custom_export_name = this->GetProperty("DEFINE_SYMBOL")) {
       this->ExportMacro = *custom_export_name;
     } else {
       std::string in = cmStrCat(this->GetName(), "_EXPORTS");
@@ -2561,6 +2559,7 @@ public:
           } break;
           case cmPolicies::OLD:
             noMessage = true;
+            break;
           case cmPolicies::REQUIRED_IF_USED:
           case cmPolicies::REQUIRED_ALWAYS:
           case cmPolicies::NEW:
@@ -2817,7 +2816,7 @@ std::string cmGeneratorTarget::GetEffectiveFolderName() const
     return effectiveFolder;
   }
 
-  cmProp targetFolder = this->GetProperty("FOLDER");
+  cmValue targetFolder = this->GetProperty("FOLDER");
   if (targetFolder) {
     effectiveFolder += *targetFolder;
   }
@@ -3045,7 +3044,7 @@ void cmTargetTraceDependencies::Trace()
     this->CurrentEntry = &this->GeneratorTarget->SourceDepends[sf];
 
     // Queue dependencies added explicitly by the user.
-    if (cmProp additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) {
+    if (cmValue additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) {
       std::vector<std::string> objDeps = cmExpandedList(*additionalDeps);
       for (std::string& objDep : objDeps) {
         if (cmSystemTools::FileIsFullPath(objDep)) {
@@ -3243,7 +3242,7 @@ void cmGeneratorTarget::GetAppleArchs(const std::string& config,
   if (!this->Makefile->IsOn("APPLE")) {
     return;
   }
-  cmProp archs = nullptr;
+  cmValue archs = nullptr;
   if (!config.empty()) {
     std::string defVarName =
       cmStrCat("OSX_ARCHITECTURES_", cmSystemTools::UpperCase(config));
@@ -3263,13 +3262,14 @@ void cmGeneratorTarget::GetAppleArchs(const std::string& config,
 void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags,
                                                  cmSourceFile const& sf) const
 {
-  cmProp lang = sf.GetProperty("LANGUAGE");
+  cmValue lang = sf.GetProperty("LANGUAGE");
   if (!lang) {
     return;
   }
 
   switch (this->GetPolicyStatusCMP0119()) {
     case cmPolicies::WARN:
+      CM_FALLTHROUGH;
     case cmPolicies::OLD:
       // The OLD behavior is to not add explicit language flags.
       return;
@@ -3568,6 +3568,7 @@ void processIncludeDirectories(cmGeneratorTarget const* tgt,
             } break;
             case cmPolicies::OLD:
               noMessage = true;
+              break;
             case cmPolicies::REQUIRED_IF_USED:
             case cmPolicies::REQUIRED_ALWAYS:
             case cmPolicies::NEW:
@@ -3644,7 +3645,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
     // If this target has ISPC sources make sure to add the header
     // directory to other compilation units
     if (cm::contains(this->GetAllConfigCompileLanguages(), "ISPC")) {
-      if (cmProp val = this->GetProperty(propertyName)) {
+      if (cmValue val = this->GetProperty(propertyName)) {
         includes.emplace_back(*val);
       } else {
         includes.emplace_back(this->GetObjectDirectory(config));
@@ -3974,7 +3975,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
   if (!config.empty()) {
     std::string configPropName =
       "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
-    cmProp configProp = this->GetProperty(configPropName);
+    cmValue configProp = this->GetProperty(configPropName);
     if (configProp) {
       switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0043)) {
         case cmPolicies::WARN: {
@@ -4049,7 +4050,7 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
     return std::string();
   }
   const cmGeneratorTarget* generatorTarget = this;
-  cmProp pchReuseFrom =
+  cmValue pchReuseFrom =
     generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
 
   const auto inserted =
@@ -4090,8 +4091,10 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
 
     const std::string filename_tmp = cmStrCat(filename, ".tmp");
     if (!pchReuseFrom) {
-      cmProp pchPrologue = this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE");
-      cmProp pchEpilogue = this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE");
+      cmValue pchPrologue =
+        this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE");
+      cmValue pchEpilogue =
+        this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE");
 
       std::string firstHeaderOnDisk;
       {
@@ -4105,7 +4108,7 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
         if (this->GetGlobalGenerator()->IsXcode()) {
           file << "#ifndef CMAKE_SKIP_PRECOMPILE_HEADERS\n";
         }
-        if (language == "CXX") {
+        if (language == "CXX" && !this->GetGlobalGenerator()->IsXcode()) {
           file << "#ifdef __cplusplus\n";
         }
         for (auto const& header_bt : headers) {
@@ -4123,7 +4126,7 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
             firstHeaderOnDisk = header_bt.Value;
           }
         }
-        if (language == "CXX") {
+        if (language == "CXX" && !this->GetGlobalGenerator()->IsXcode()) {
           file << "#endif // __cplusplus\n";
         }
         if (this->GetGlobalGenerator()->IsXcode()) {
@@ -4162,7 +4165,7 @@ std::string cmGeneratorTarget::GetPchSource(const std::string& config,
     std::string& filename = inserted.first->second;
 
     const cmGeneratorTarget* generatorTarget = this;
-    cmProp pchReuseFrom =
+    cmValue pchReuseFrom =
       generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
     if (pchReuseFrom) {
       generatorTarget =
@@ -4260,7 +4263,7 @@ std::string cmGeneratorTarget::GetPchFile(const std::string& config,
       };
 
       cmGeneratorTarget* generatorTarget = this;
-      cmProp pchReuseFrom =
+      cmValue pchReuseFrom =
         generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
       if (pchReuseFrom) {
         generatorTarget =
@@ -4466,6 +4469,13 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
 
   // Last step: replace "LINKER:" prefixed elements by
   // actual linker wrapper
+  return this->ResolveLinkerWrapper(result, language);
+}
+
+std::vector<BT<std::string>>& cmGeneratorTarget::ResolveLinkerWrapper(
+  std::vector<BT<std::string>>& result, const std::string& language) const
+{
+  // replace "LINKER:" prefixed elements by actual linker wrapper
   const std::string wrapper(this->Makefile->GetSafeDefinition(
     "CMAKE_" + language +
     (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG"
@@ -4549,7 +4559,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions(
                                              nullptr, nullptr);
 
   EvaluatedTargetPropertyEntries entries;
-  if (cmProp linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
+  if (cmValue linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
     std::vector<std::string> options = cmExpandedList(*linkOptions);
     for (const auto& option : options) {
       std::unique_ptr<TargetPropertyEntry> entry =
@@ -4700,7 +4710,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends(
                                              nullptr);
 
   EvaluatedTargetPropertyEntries entries;
-  if (cmProp linkDepends = this->GetProperty("LINK_DEPENDS")) {
+  if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) {
     std::vector<std::string> depends = cmExpandedList(*linkDepends);
     for (const auto& depend : depends) {
       std::unique_ptr<TargetPropertyEntry> entry =
@@ -4781,7 +4791,7 @@ bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const
     }
 
     std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang);
-    cmProp currentLanguageStandard = this->GetLanguageStandard(lang, config);
+    cmValue currentLanguageStandard = this->GetLanguageStandard(lang, config);
 
     std::string newRequiredStandard;
     if (!standardResolver.GetNewRequiredStandard(
@@ -4821,7 +4831,7 @@ bool cmGeneratorTarget::ComputeCompileFeatures(
         this->LanguageStandardMap[key] = *standardToCopy;
         generatorTargetLanguageStandard = &this->LanguageStandardMap[key];
       } else {
-        cmProp defaultStandard = this->Makefile->GetDefinition(
+        cmValue defaultStandard = this->Makefile->GetDefinition(
           cmStrCat("CMAKE_", language.second, "_STANDARD_DEFAULT"));
         if (defaultStandard) {
           this->LanguageStandardMap[key] = BTs<std::string>(*defaultStandard);
@@ -4924,8 +4934,8 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
   }
 
   // Check for library version properties.
-  cmProp version = this->GetProperty("VERSION");
-  cmProp soversion = this->GetProperty("SOVERSION");
+  cmValue version = this->GetProperty("VERSION");
+  cmValue soversion = this->GetProperty("SOVERSION");
   if (!this->HasSOName(config) ||
       this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") ||
       this->IsFrameworkOnApple()) {
@@ -4966,11 +4976,11 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
     // The library's soname.
     this->ComputeVersionedName(targetNames.SharedObject, prefix,
                                targetNames.Base, suffix, targetNames.Output,
-                               cmToCStr(soversion));
+                               soversion);
 
     // The library's real name on disk.
     this->ComputeVersionedName(targetNames.Real, prefix, targetNames.Base,
-                               suffix, targetNames.Output, cmToCStr(version));
+                               suffix, targetNames.Output, version);
   }
 
   // The import library name.
@@ -5003,10 +5013,10 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
 // This versioning is supported only for executables and then only
 // when the platform supports symbolic links.
 #if defined(_WIN32) && !defined(__CYGWIN__)
-  const char* version = nullptr;
+  cmValue version;
 #else
   // Check for executable version properties.
-  const char* version = cmToCStr(this->GetProperty("VERSION"));
+  cmValue version = this->GetProperty("VERSION");
   if (this->GetType() != cmStateEnums::EXECUTABLE ||
       this->Makefile->IsOn("XCODE")) {
     version = nullptr;
@@ -5030,7 +5040,7 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
 #endif
   if (version) {
     targetNames.Real += "-";
-    targetNames.Real += version;
+    targetNames.Real += *version;
   }
 #if defined(__CYGWIN__)
   targetNames.Real += suffix;
@@ -5100,8 +5110,8 @@ void cmGeneratorTarget::GetFullNameInternal(
 
   // retrieve prefix and suffix
   std::string ll = this->GetLinkerLanguage(config);
-  cmProp targetPrefix = this->GetFilePrefixInternal(config, artifact, ll);
-  cmProp targetSuffix = this->GetFileSuffixInternal(config, artifact, ll);
+  cmValue targetPrefix = this->GetFilePrefixInternal(config, artifact, ll);
+  cmValue targetSuffix = this->GetFileSuffixInternal(config, artifact, ll);
 
   // The implib option is only allowed for shared libraries, module
   // libraries, and executables.
@@ -5119,13 +5129,13 @@ void cmGeneratorTarget::GetFullNameInternal(
   if (this->IsFrameworkOnApple()) {
     fw_prefix =
       cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/');
-    targetPrefix = &fw_prefix;
+    targetPrefix = cmValue(fw_prefix);
     targetSuffix = nullptr;
   }
 
   if (this->IsCFBundleOnApple()) {
     fw_prefix = cmStrCat(this->GetCFBundleDirectory(config, FullLevel), '/');
-    targetPrefix = &fw_prefix;
+    targetPrefix = cmValue(fw_prefix);
     targetSuffix = nullptr;
   }
 
@@ -5141,13 +5151,13 @@ void cmGeneratorTarget::GetFullNameInternal(
   // EXECUTABLE_SUFFIX attribute.
   if (this->IsFrameworkOnApple() &&
       this->GetGlobalGenerator()->GetName() == "Xcode") {
-    targetSuffix = &configPostfix;
+    targetSuffix = cmValue(configPostfix);
   } else {
     outBase += configPostfix;
   }
 
   // Name shared libraries with their version number on some platforms.
-  if (cmProp soversion = this->GetProperty("SOVERSION")) {
+  if (cmValue soversion = this->GetProperty("SOVERSION")) {
     if (this->GetType() == cmStateEnums::SHARED_LIBRARY &&
         !isImportedLibraryArtifact &&
         this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")) {
@@ -5183,7 +5193,7 @@ std::string cmGeneratorTarget::GetPDBOutputName(
   props.emplace_back("PDB_NAME");
 
   for (std::string const& p : props) {
-    if (cmProp outName = this->GetProperty(p)) {
+    if (cmValue outName = this->GetProperty(p)) {
       base = *outName;
       break;
     }
@@ -5210,7 +5220,7 @@ std::string cmGeneratorTarget::GetPDBName(const std::string& config) const
   props.emplace_back("PDB_NAME");
 
   for (std::string const& p : props) {
-    if (cmProp outName = this->GetProperty(p)) {
+    if (cmValue outName = this->GetProperty(p)) {
       base = *outName;
       break;
     }
@@ -5293,7 +5303,7 @@ cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const
   } else {
     // Handle the MACOSX_PACKAGE_LOCATION property on source files that
     // were not listed in one of the other lists.
-    if (cmProp location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) {
+    if (cmValue location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) {
       flags.MacFolder = location->c_str();
       const bool stripResources =
         this->GlobalGenerator->ShouldStripResourcePath(this->Makefile);
@@ -5323,7 +5333,7 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const
   this->SourceFileFlagsConstructed = true;
 
   // Process public headers to mark the source files.
-  if (cmProp files = this->GetProperty("PUBLIC_HEADER")) {
+  if (cmValue files = this->GetProperty("PUBLIC_HEADER")) {
     std::vector<std::string> relFiles = cmExpandedList(*files);
     for (std::string const& relFile : relFiles) {
       if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
@@ -5336,7 +5346,7 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const
 
   // Process private headers after public headers so that they take
   // precedence if a file is listed in both.
-  if (cmProp files = this->GetProperty("PRIVATE_HEADER")) {
+  if (cmValue files = this->GetProperty("PRIVATE_HEADER")) {
     std::vector<std::string> relFiles = cmExpandedList(*files);
     for (std::string const& relFile : relFiles) {
       if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
@@ -5348,7 +5358,7 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const
   }
 
   // Mark sources listed as resources.
-  if (cmProp files = this->GetProperty("RESOURCE")) {
+  if (cmValue files = this->GetProperty("RESOURCE")) {
     std::vector<std::string> relFiles = cmExpandedList(*files);
     for (std::string const& relFile : relFiles) {
       if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) {
@@ -5376,7 +5386,7 @@ cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const
       this->GetLinkImplementationClosure(config);
     for (cmGeneratorTarget const* li : deps) {
 #define CM_READ_COMPATIBLE_INTERFACE(X, x)                                    \
-  if (cmProp prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) {            \
+  if (cmValue prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) {           \
     std::vector<std::string> props;                                           \
     cmExpandList(*prop, props);                                               \
     compat.Props##x.insert(props.begin(), props.end());                       \
@@ -5486,7 +5496,7 @@ void checkPropertyConsistency(cmGeneratorTarget const* depender,
                               const std::string& config, CompatibleType t,
                               PropertyType* /*unused*/)
 {
-  cmProp prop = dependee->GetProperty(propName);
+  cmValue prop = dependee->GetProperty(propName);
   if (!prop) {
     return;
   }
@@ -5672,6 +5682,11 @@ std::string valueAsString<std::string>(std::string value)
   return value;
 }
 template <>
+std::string valueAsString<cmValue>(cmValue value)
+{
+  return value ? value : std::string("(unset)");
+}
+template <>
 std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/)
 {
   return "(unset)";
@@ -5721,7 +5736,7 @@ bool getTypedProperty<bool>(cmGeneratorTarget const* tgt,
     return tgt->GetPropertyAsBool(prop);
   }
 
-  cmProp value = tgt->GetProperty(prop);
+  cmValue value = tgt->GetProperty(prop);
   return cmIsOn(genexInterpreter->Evaluate(value ? *value : "", prop));
 }
 
@@ -5730,10 +5745,10 @@ const char* getTypedProperty<const char*>(
   cmGeneratorTarget const* tgt, const std::string& prop,
   cmGeneratorExpressionInterpreter* genexInterpreter)
 {
-  cmProp value = tgt->GetProperty(prop);
+  cmValue value = tgt->GetProperty(prop);
 
   if (genexInterpreter == nullptr) {
-    return cmToCStr(value);
+    return value.GetCStr();
   }
 
   return genexInterpreter->Evaluate(value ? *value : "", prop).c_str();
@@ -5744,10 +5759,10 @@ std::string getTypedProperty<std::string>(
   cmGeneratorTarget const* tgt, const std::string& prop,
   cmGeneratorExpressionInterpreter* genexInterpreter)
 {
-  cmProp value = tgt->GetProperty(prop);
+  cmValue value = tgt->GetProperty(prop);
 
   if (genexInterpreter == nullptr) {
-    return valueAsString(cmToCStr(value));
+    return valueAsString(value);
   }
 
   return genexInterpreter->Evaluate(value ? *value : "", prop);
@@ -6121,7 +6136,7 @@ void cmGeneratorTarget::GetTargetVersion(const std::string& property,
 
   assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
 
-  if (cmProp version = this->GetProperty(property)) {
+  if (cmValue version = this->GetProperty(property)) {
     // Try to parse the version number and store the results that were
     // successfully parsed.
     int parsed_major;
@@ -6149,12 +6164,12 @@ std::string cmGeneratorTarget::GetRuntimeLinkLibrary(
 {
   // This is activated by the presence of a default selection whether or
   // not it is overridden by a property.
-  cmProp runtimeLibraryDefault = this->Makefile->GetDefinition(
+  cmValue runtimeLibraryDefault = this->Makefile->GetDefinition(
     cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT"));
   if (!cmNonempty(runtimeLibraryDefault)) {
     return std::string();
   }
-  cmProp runtimeLibraryValue =
+  cmValue runtimeLibraryValue =
     this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY"));
   if (!runtimeLibraryValue) {
     runtimeLibraryValue = runtimeLibraryDefault;
@@ -6175,12 +6190,21 @@ std::string cmGeneratorTarget::GetFortranModuleDirectory(
   return this->FortranModuleDirectory;
 }
 
+bool cmGeneratorTarget::IsFortranBuildingInstrinsicModules() const
+{
+  if (cmValue prop =
+        this->GetProperty("Fortran_BUILDING_INSTRINSIC_MODULES")) {
+    return cmIsOn(*prop);
+  }
+  return false;
+}
+
 std::string cmGeneratorTarget::CreateFortranModuleDirectory(
   std::string const& working_dir) const
 {
   std::string mod_dir;
   std::string target_mod_dir;
-  if (cmProp prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) {
+  if (cmValue prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) {
     target_mod_dir = *prop;
   } else {
     std::string const& default_mod_dir =
@@ -6189,7 +6213,7 @@ std::string cmGeneratorTarget::CreateFortranModuleDirectory(
       target_mod_dir = default_mod_dir;
     }
   }
-  cmProp moddir_flag =
+  cmValue moddir_flag =
     this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG");
   if (!target_mod_dir.empty() && moddir_flag) {
     // Compute the full path to the module directory.
@@ -6272,26 +6296,23 @@ std::string cmGeneratorTarget::GetFrameworkVersion() const
 {
   assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
 
-  if (cmProp fversion = this->GetProperty("FRAMEWORK_VERSION")) {
+  if (cmValue fversion = this->GetProperty("FRAMEWORK_VERSION")) {
     return *fversion;
   }
-  if (cmProp tversion = this->GetProperty("VERSION")) {
+  if (cmValue tversion = this->GetProperty("VERSION")) {
     return *tversion;
   }
   return "A";
 }
 
-void cmGeneratorTarget::ComputeVersionedName(std::string& vName,
-                                             std::string const& prefix,
-                                             std::string const& base,
-                                             std::string const& suffix,
-                                             std::string const& name,
-                                             const char* version) const
+void cmGeneratorTarget::ComputeVersionedName(
+  std::string& vName, std::string const& prefix, std::string const& base,
+  std::string const& suffix, std::string const& name, cmValue version) const
 {
   vName = this->Makefile->IsOn("APPLE") ? (prefix + base) : name;
   if (version) {
     vName += ".";
-    vName += version;
+    vName += *version;
   }
   vName += this->Makefile->IsOn("APPLE") ? suffix : std::string();
 }
@@ -6358,16 +6379,16 @@ cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem(
   if (name == this->GetName() || name.empty()) {
     return maybeItem;
   }
-  maybeItem = this->ResolveLinkItem(name, bt, scope->LG);
+  maybeItem = this->ResolveLinkItem(BT<std::string>(name, bt), scope->LG);
   return maybeItem;
 }
 
-void cmGeneratorTarget::ExpandLinkItems(
-  std::string const& prop, std::string const& value, std::string const& config,
-  cmGeneratorTarget const* headTarget, bool usage_requirements_only,
-  std::vector<cmLinkItem>& items, std::vector<cmLinkItem>& objects,
-  bool& hadHeadSensitiveCondition, bool& hadContextSensitiveCondition,
-  bool& hadLinkLanguageSensitiveCondition) const
+void cmGeneratorTarget::ExpandLinkItems(std::string const& prop,
+                                        std::string const& value,
+                                        std::string const& config,
+                                        cmGeneratorTarget const* headTarget,
+                                        bool usage_requirements_only,
+                                        cmLinkInterface& iface) const
 {
   // Keep this logic in sync with ComputeLinkImplementationLibraries.
   cmGeneratorExpression ge;
@@ -6389,24 +6410,27 @@ void cmGeneratorTarget::ExpandLinkItems(
   for (std::string const& lib : libs) {
     if (cm::optional<cmLinkItem> maybeItem =
           this->LookupLinkItem(lib, cge->GetBacktrace(), &scope)) {
-      if (!maybeItem->Target) {
+      cmLinkItem item = std::move(*maybeItem);
+
+      if (!item.Target) {
         // Report explicitly linked object files separately.
-        std::string const& maybeObj = maybeItem->AsStr();
+        std::string const& maybeObj = item.AsStr();
         if (cmSystemTools::FileIsFullPath(maybeObj)) {
           cmSourceFile const* sf =
             mf->GetSource(maybeObj, cmSourceFileLocationKind::Known);
           if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
-            objects.emplace_back(std::move(*maybeItem));
+            iface.Objects.emplace_back(std::move(item));
             continue;
           }
         }
       }
-      items.emplace_back(std::move(*maybeItem));
+
+      iface.Libraries.emplace_back(std::move(item));
     }
   }
-  hadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition();
-  hadContextSensitiveCondition = cge->GetHadContextSensitiveCondition();
-  hadLinkLanguageSensitiveCondition =
+  iface.HadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition();
+  iface.HadContextSensitiveCondition = cge->GetHadContextSensitiveCondition();
+  iface.HadLinkLanguageSensitiveCondition =
     cge->GetHadLinkLanguageSensitiveCondition();
 }
 
@@ -6531,9 +6555,9 @@ void cmGeneratorTarget::ComputeLinkInterface(
     // How many repetitions are needed if this library has cyclic
     // dependencies?
     std::string propName = cmStrCat("LINK_INTERFACE_MULTIPLICITY", suffix);
-    if (cmProp config_reps = this->GetProperty(propName)) {
+    if (cmValue config_reps = this->GetProperty(propName)) {
       sscanf(config_reps->c_str(), "%u", &iface.Multiplicity);
-    } else if (cmProp reps =
+    } else if (cmValue reps =
                  this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) {
       sscanf(reps->c_str(), "%u", &iface.Multiplicity);
     }
@@ -6690,14 +6714,14 @@ bool cmGeneratorTarget::ComputeOutputDir(const std::string& config,
   }
 
   // Select an output directory.
-  if (cmProp config_outdir = this->GetProperty(configProp)) {
+  if (cmValue config_outdir = this->GetProperty(configProp)) {
     // Use the user-specified per-configuration output directory.
     out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
                                           config, this);
 
     // Skip per-configuration subdirectory.
     conf.clear();
-  } else if (cmProp outdir = this->GetProperty(propertyName)) {
+  } else if (cmValue outdir = this->GetProperty(propertyName)) {
     // Use the user-specified output directory.
     out = cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator,
                                           config, this);
@@ -6760,14 +6784,14 @@ bool cmGeneratorTarget::ComputePDBOutputDir(const std::string& kind,
   }
 
   // Select an output directory.
-  if (cmProp config_outdir = this->GetProperty(configProp)) {
+  if (cmValue config_outdir = this->GetProperty(configProp)) {
     // Use the user-specified per-configuration output directory.
     out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
                                           config);
 
     // Skip per-configuration subdirectory.
     conf.clear();
-  } else if (cmProp outdir = this->GetProperty(propertyName)) {
+  } else if (cmValue outdir = this->GetProperty(propertyName)) {
     // Use the user-specified output directory.
     out =
       cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config);
@@ -6820,7 +6844,7 @@ bool cmGeneratorTarget::GetRPATH(const std::string& config,
                                  const std::string& prop,
                                  std::string& rpath) const
 {
-  cmProp value = this->GetProperty(prop);
+  cmValue value = this->GetProperty(prop);
   if (!value) {
     return false;
   }
@@ -6845,7 +6869,7 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
 
   // An explicit list of interface libraries may be set for shared
   // libraries and executables that export symbols.
-  cmProp explicitLibraries = nullptr;
+  cmValue explicitLibraries = nullptr;
   std::string linkIfaceProp;
   bool const cmp0022NEW = (this->GetPolicyStatusCMP0022() != cmPolicies::OLD &&
                            this->GetPolicyStatusCMP0022() != cmPolicies::WARN);
@@ -6874,7 +6898,7 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
       !this->PolicyWarnedCMP0022) {
     // Compare the explicitly set old link interface properties to the
     // preferred new link interface property one and warn if different.
-    cmProp newExplicitLibraries =
+    cmValue newExplicitLibraries =
       this->GetProperty("INTERFACE_LINK_LIBRARIES");
     if (newExplicitLibraries &&
         (*newExplicitLibraries != *explicitLibraries)) {
@@ -6903,23 +6927,20 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
     return;
   }
   iface.Exists = true;
+
+  // If CMP0022 is NEW then the plain tll signature sets the
+  // INTERFACE_LINK_LIBRARIES property.  Even if the project
+  // clears it, the link interface is still explicit.
   iface.Explicit = cmp0022NEW || explicitLibraries;
 
   if (explicitLibraries) {
     // The interface libraries have been explicitly set.
     this->ExpandLinkItems(linkIfaceProp, *explicitLibraries, config,
-                          headTarget, usage_requirements_only, iface.Libraries,
-                          iface.Objects, iface.HadHeadSensitiveCondition,
-                          iface.HadContextSensitiveCondition,
-                          iface.HadLinkLanguageSensitiveCondition);
-    return;
+                          headTarget, usage_requirements_only, iface);
   }
 
-  // If CMP0022 is NEW then the plain tll signature sets the
-  // INTERFACE_LINK_LIBRARIES, so if we get here then the project
-  // cleared the property explicitly and we should not fall back
-  // to the link implementation.
-  if (cmp0022NEW) {
+  // If the link interface is explicit, do not fall back to the link impl.
+  if (iface.Explicit) {
     return;
   }
 
@@ -6932,22 +6953,15 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
         !this->PolicyWarnedCMP0022 && !usage_requirements_only) {
       // Compare the link implementation fallback link interface to the
       // preferred new link interface property and warn if different.
-      std::vector<cmLinkItem> ifaceLibs;
-      std::vector<cmLinkItem> ifaceObjects;
+      cmLinkInterface ifaceNew;
       static const std::string newProp = "INTERFACE_LINK_LIBRARIES";
-      if (cmProp newExplicitLibraries = this->GetProperty(newProp)) {
-        bool hadHeadSensitiveConditionDummy = false;
-        bool hadContextSensitiveConditionDummy = false;
-        bool hadLinkLanguageSensitiveConditionDummy = false;
+      if (cmValue newExplicitLibraries = this->GetProperty(newProp)) {
         this->ExpandLinkItems(newProp, *newExplicitLibraries, config,
-                              headTarget, usage_requirements_only, ifaceLibs,
-                              ifaceObjects, hadHeadSensitiveConditionDummy,
-                              hadContextSensitiveConditionDummy,
-                              hadLinkLanguageSensitiveConditionDummy);
+                              headTarget, usage_requirements_only, ifaceNew);
       }
-      if (ifaceLibs != iface.Libraries) {
+      if (ifaceNew.Libraries != iface.Libraries) {
         std::string oldLibraries = cmJoin(impl->Libraries, ";");
-        std::string newLibraries = cmJoin(ifaceLibs, ";");
+        std::string newLibraries = cmJoin(ifaceNew.Libraries, ";");
         if (oldLibraries.empty()) {
           oldLibraries = "(empty)";
         }
@@ -7009,7 +7023,7 @@ std::vector<ValueType> computeImplicitLanguageTargets(
 
   std::string const& runtimeLibrary =
     currentTarget->GetRuntimeLinkLibrary(lang, config);
-  if (cmProp runtimeLinkOptions = currentTarget->Makefile->GetDefinition(
+  if (cmValue runtimeLinkOptions = currentTarget->Makefile->GetDefinition(
         "CMAKE_" + lang + "_RUNTIME_LIBRARIES_" + runtimeLibrary)) {
     std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions);
     result.reserve(libsVec.size());
@@ -7085,10 +7099,7 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface(
     iface.Multiplicity = info->Multiplicity;
     cmExpandList(info->Languages, iface.Languages);
     this->ExpandLinkItems(info->LibrariesProp, info->Libraries, config,
-                          headTarget, usage_requirements_only, iface.Libraries,
-                          iface.Objects, iface.HadHeadSensitiveCondition,
-                          iface.HadContextSensitiveCondition,
-                          iface.HadLinkLanguageSensitiveCondition);
+                          headTarget, usage_requirements_only, iface);
     std::vector<std::string> deps = cmExpandedList(info->SharedDeps);
     LookupLinkItemScope scope{ this->LocalGenerator };
     for (std::string const& dep : deps) {
@@ -7150,8 +7161,8 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
   // Initialize members.
   info.NoSOName = false;
 
-  cmProp loc = nullptr;
-  cmProp imp = nullptr;
+  cmValue loc = nullptr;
+  cmValue imp = nullptr;
   std::string suffix;
   if (!this->Target->GetMappedConfig(desired_config, loc, imp, suffix)) {
     return;
@@ -7160,7 +7171,7 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
   // Get the link interface.
   {
     std::string linkProp = "INTERFACE_LINK_LIBRARIES";
-    cmProp propertyLibs = this->GetProperty(linkProp);
+    cmValue propertyLibs = this->GetProperty(linkProp);
 
     if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
       if (!propertyLibs) {
@@ -7193,9 +7204,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
     info.Location = *loc;
   } else {
     std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix);
-    if (cmProp config_location = this->GetProperty(impProp)) {
+    if (cmValue config_location = this->GetProperty(impProp)) {
       info.Location = *config_location;
-    } else if (cmProp location = this->GetProperty("IMPORTED_LOCATION")) {
+    } else if (cmValue location = this->GetProperty("IMPORTED_LOCATION")) {
       info.Location = *location;
     }
   }
@@ -7203,9 +7214,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
   // Get the soname.
   if (this->GetType() == cmStateEnums::SHARED_LIBRARY) {
     std::string soProp = cmStrCat("IMPORTED_SONAME", suffix);
-    if (cmProp config_soname = this->GetProperty(soProp)) {
+    if (cmValue config_soname = this->GetProperty(soProp)) {
       info.SOName = *config_soname;
-    } else if (cmProp soname = this->GetProperty("IMPORTED_SONAME")) {
+    } else if (cmValue soname = this->GetProperty("IMPORTED_SONAME")) {
       info.SOName = *soname;
     }
   }
@@ -7213,9 +7224,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
   // Get the "no-soname" mark.
   if (this->GetType() == cmStateEnums::SHARED_LIBRARY) {
     std::string soProp = cmStrCat("IMPORTED_NO_SONAME", suffix);
-    if (cmProp config_no_soname = this->GetProperty(soProp)) {
+    if (cmValue config_no_soname = this->GetProperty(soProp)) {
       info.NoSOName = cmIsOn(*config_no_soname);
-    } else if (cmProp no_soname = this->GetProperty("IMPORTED_NO_SONAME")) {
+    } else if (cmValue no_soname = this->GetProperty("IMPORTED_NO_SONAME")) {
       info.NoSOName = cmIsOn(*no_soname);
     }
   }
@@ -7226,9 +7237,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
   } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
              this->IsExecutableWithExports()) {
     std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
-    if (cmProp config_implib = this->GetProperty(impProp)) {
+    if (cmValue config_implib = this->GetProperty(impProp)) {
       info.ImportLibrary = *config_implib;
-    } else if (cmProp implib = this->GetProperty("IMPORTED_IMPLIB")) {
+    } else if (cmValue implib = this->GetProperty("IMPORTED_IMPLIB")) {
       info.ImportLibrary = *implib;
     }
   }
@@ -7237,9 +7248,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
   {
     std::string linkProp =
       cmStrCat("IMPORTED_LINK_DEPENDENT_LIBRARIES", suffix);
-    if (cmProp config_libs = this->GetProperty(linkProp)) {
+    if (cmValue config_libs = this->GetProperty(linkProp)) {
       info.SharedDeps = *config_libs;
-    } else if (cmProp libs =
+    } else if (cmValue libs =
                  this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES")) {
       info.SharedDeps = *libs;
     }
@@ -7249,9 +7260,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
   if (this->LinkLanguagePropagatesToDependents()) {
     std::string linkProp =
       cmStrCat("IMPORTED_LINK_INTERFACE_LANGUAGES", suffix);
-    if (cmProp config_libs = this->GetProperty(linkProp)) {
+    if (cmValue config_libs = this->GetProperty(linkProp)) {
       info.Languages = *config_libs;
-    } else if (cmProp libs =
+    } else if (cmValue libs =
                  this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES")) {
       info.Languages = *libs;
     }
@@ -7260,9 +7271,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
   // Get information if target is managed assembly.
   {
     std::string linkProp = "IMPORTED_COMMON_LANGUAGE_RUNTIME";
-    if (cmProp pc = this->GetProperty(linkProp + suffix)) {
+    if (cmValue pc = this->GetProperty(linkProp + suffix)) {
       info.Managed = this->CheckManagedType(*pc);
-    } else if (cmProp p = this->GetProperty(linkProp)) {
+    } else if (cmValue p = this->GetProperty(linkProp)) {
       info.Managed = this->CheckManagedType(*p);
     }
   }
@@ -7271,9 +7282,9 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
   if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
     std::string linkProp =
       cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix);
-    if (cmProp config_reps = this->GetProperty(linkProp)) {
+    if (cmValue config_reps = this->GetProperty(linkProp)) {
       sscanf(config_reps->c_str(), "%u", &info.Multiplicity);
-    } else if (cmProp reps =
+    } else if (cmValue reps =
                  this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) {
       sscanf(reps->c_str(), "%u", &info.Multiplicity);
     }
@@ -7381,9 +7392,9 @@ void cmGeneratorTarget::GetObjectLibrariesCMP0026(
   // there is no cmGeneratorTarget at configure-time, so search the SOURCES
   // for TARGET_OBJECTS instead for backwards compatibility with OLD
   // behavior of CMP0024 and CMP0026 only.
-  cmStringRange rng = this->Target->GetSourceEntries();
-  for (std::string const& entry : rng) {
-    std::vector<std::string> files = cmExpandedList(entry);
+  cmBTStringRange rng = this->Target->GetSourceEntries();
+  for (auto const& entry : rng) {
+    std::vector<std::string> files = cmExpandedList(entry.Value);
     for (std::string const& li : files) {
       if (cmHasLiteralPrefix(li, "$<TARGET_OBJECTS:") && li.back() == '>') {
         std::string objLibName = li.substr(17, li.size() - 18);
@@ -7426,6 +7437,7 @@ std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const
         cm->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
                          this->GetBacktrace());
       }
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         break;
       case cmPolicies::NEW: {
@@ -7452,14 +7464,14 @@ std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const
 
 bool cmGeneratorTarget::IsDeprecated() const
 {
-  cmProp deprecation = this->GetProperty("DEPRECATION");
+  cmValue deprecation = this->GetProperty("DEPRECATION");
   return cmNonempty(deprecation);
 }
 
 std::string cmGeneratorTarget::GetDeprecation() const
 {
   // find DEPRECATION property
-  if (cmProp deprecation = this->GetProperty("DEPRECATION")) {
+  if (cmValue deprecation = this->GetProperty("DEPRECATION")) {
     return *deprecation;
   }
   return std::string();
@@ -7530,7 +7542,7 @@ bool cmGeneratorTarget::IsCSharpOnly() const
   std::set<std::string> languages = this->GetAllConfigCompileLanguages();
   // Consider an explicit linker language property, but *not* the
   // computed linker language that may depend on linked targets.
-  cmProp linkLang = this->GetProperty("LINKER_LANGUAGE");
+  cmValue linkLang = this->GetProperty("LINKER_LANGUAGE");
   if (cmNonempty(linkLang)) {
     languages.insert(*linkLang);
   }
@@ -7611,23 +7623,21 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
 {
   cmLocalGenerator const* lg = this->LocalGenerator;
   cmMakefile const* mf = lg->GetMakefile();
-  cmStringRange entryRange = this->Target->GetLinkImplementationEntries();
-  cmBacktraceRange btRange = this->Target->GetLinkImplementationBacktraces();
-  cmBacktraceRange::const_iterator btIt = btRange.begin();
+  cmBTStringRange entryRange = this->Target->GetLinkImplementationEntries();
   // Collect libraries directly linked in this configuration.
-  for (cmStringRange::const_iterator le = entryRange.begin(),
-                                     end = entryRange.end();
-       le != end; ++le, ++btIt) {
+  for (auto const& entry : entryRange) {
     std::vector<std::string> llibs;
     // Keep this logic in sync with ExpandLinkItems.
     cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr,
                                                nullptr);
-    cmGeneratorExpression ge(*btIt);
-    std::unique_ptr<cmCompiledGeneratorExpression> const cge = ge.Parse(*le);
+    cmGeneratorExpression ge(entry.Backtrace);
+    std::unique_ptr<cmCompiledGeneratorExpression> const cge =
+      ge.Parse(entry.Value);
     cge->SetEvaluateForBuildsystem(true);
     std::string const& evaluated =
       cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr,
                     this->LinkerLanguage);
+    bool const fromGenex = evaluated != entry.Value;
     cmExpandList(evaluated, llibs);
     if (cge->GetHadHeadSensitiveCondition()) {
       impl.HadHeadSensitiveCondition = true;
@@ -7665,6 +7675,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
             } break;
             case cmPolicies::OLD:
               noMessage = true;
+              break;
             case cmPolicies::REQUIRED_IF_USED:
             case cmPolicies::REQUIRED_ALWAYS:
             case cmPolicies::NEW:
@@ -7685,7 +7696,8 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
       }
 
       // The entry is meant for this configuration.
-      cmLinkItem item = this->ResolveLinkItem(name, *btIt, lg);
+      cmLinkItem item =
+        this->ResolveLinkItem(BT<std::string>(name, entry.Backtrace), lg);
       if (!item.Target) {
         // Report explicitly linked object files separately.
         std::string const& maybeObj = item.AsStr();
@@ -7699,7 +7711,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
         }
       }
 
-      impl.Libraries.emplace_back(std::move(item), evaluated != *le);
+      impl.Libraries.emplace_back(std::move(item), fromGenex);
     }
 
     std::set<std::string> const& seenProps = cge->GetSeenTargetProperties();
@@ -7727,7 +7739,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
       }
       // Support OLD behavior for CMP0003.
       impl.WrongConfigLibraries.push_back(
-        this->ResolveLinkItem(name, cmListFileBacktrace()));
+        this->ResolveLinkItem(BT<std::string>(name)));
     }
   }
 }
@@ -7753,16 +7765,16 @@ cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
 }
 
 cmLinkItem cmGeneratorTarget::ResolveLinkItem(
-  std::string const& name, cmListFileBacktrace const& bt) const
+  BT<std::string> const& name) const
 {
-  return this->ResolveLinkItem(name, bt, this->LocalGenerator);
+  return this->ResolveLinkItem(name, this->LocalGenerator);
 }
 
-cmLinkItem cmGeneratorTarget::ResolveLinkItem(std::string const& name,
-                                              cmListFileBacktrace const& bt,
+cmLinkItem cmGeneratorTarget::ResolveLinkItem(BT<std::string> const& name,
                                               cmLocalGenerator const* lg) const
 {
-  TargetOrString resolved = this->ResolveTargetReference(name, lg);
+  auto bt = name.Backtrace;
+  TargetOrString resolved = this->ResolveTargetReference(name.Value, lg);
 
   if (!resolved.Target) {
     return cmLinkItem(resolved.String, false, bt);
@@ -7940,7 +7952,7 @@ cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType(
   }
 
   // Check for explicitly set clr target property.
-  if (cmProp clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
+  if (cmValue clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
     return this->CheckManagedType(*clr);
   }
 
index 6d2aa85..9906963 100644 (file)
@@ -19,8 +19,8 @@
 #include "cmLinkItem.h"
 #include "cmListFileCache.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
+#include "cmValue.h"
 
 class cmComputeLinkInformation;
 class cmCustomCommand;
@@ -89,7 +89,7 @@ public:
 
   std::vector<std::string> GetPropertyKeys() const;
   //! Might return a nullptr if the property is not set or invalid
-  cmProp GetProperty(const std::string& prop) const;
+  cmValue GetProperty(const std::string& prop) const;
   //! Always returns a valid pointer
   std::string const& GetSafeProperty(std::string const& prop) const;
   bool GetPropertyAsBool(const std::string& prop) const;
@@ -163,10 +163,10 @@ public:
   BTs<std::string> const* GetLanguageStandardProperty(
     std::string const& lang, std::string const& config) const;
 
-  cmProp GetLanguageStandard(std::string const& lang,
-                             std::string const& config) const;
+  cmValue GetLanguageStandard(std::string const& lang,
+                              std::string const& config) const;
 
-  cmProp GetLanguageExtensions(std::string const& lang) const;
+  cmValue GetLanguageExtensions(std::string const& lang) const;
 
   bool GetLanguageStandardRequired(std::string const& lang) const;
 
@@ -187,8 +187,8 @@ public:
 
   void ComputeObjectMapping();
 
-  cmProp GetFeature(const std::string& feature,
-                    const std::string& config) const;
+  cmValue GetFeature(const std::string& feature,
+                     const std::string& config) const;
 
   const char* GetLinkPIEProperty(const std::string& config) const;
 
@@ -221,7 +221,7 @@ public:
     {
       this->PreviousState = target.SetDeviceLink(true);
     }
-    ~DeviceLinkSetter() { this->Target.SetDeviceLink(this->PreviousState); };
+    ~DeviceLinkSetter() { this->Target.SetDeviceLink(this->PreviousState); }
 
   private:
     cmGeneratorTarget& Target;
@@ -409,10 +409,8 @@ public:
   TargetOrString ResolveTargetReference(std::string const& name,
                                         cmLocalGenerator const* lg) const;
 
-  cmLinkItem ResolveLinkItem(std::string const& name,
-                             cmListFileBacktrace const& bt) const;
-  cmLinkItem ResolveLinkItem(std::string const& name,
-                             cmListFileBacktrace const& bt,
+  cmLinkItem ResolveLinkItem(BT<std::string> const& name) const;
+  cmLinkItem ResolveLinkItem(BT<std::string> const& name,
                              cmLocalGenerator const* lg) const;
 
   // Compute the set of languages compiled by the target.  This is
@@ -498,6 +496,9 @@ public:
   std::vector<BT<std::string>> GetLinkOptions(
     std::string const& config, std::string const& language) const;
 
+  std::vector<BT<std::string>>& ResolveLinkerWrapper(
+    std::vector<BT<std::string>>& result, const std::string& language) const;
+
   void GetStaticLibraryLinkOptions(std::vector<std::string>& result,
                                    const std::string& config,
                                    const std::string& language) const;
@@ -832,8 +833,9 @@ public:
                                     std::string const& config) const;
 
   std::string GetFortranModuleDirectory(std::string const& working_dir) const;
+  bool IsFortranBuildingInstrinsicModules() const;
 
-  const std::string& GetSourcesProperty() const;
+  cmValue GetSourcesProperty() const;
 
   void AddISPCGeneratedHeader(std::string const& header,
                               std::string const& config);
@@ -864,6 +866,11 @@ private:
   mutable std::map<cmSourceFile const*, std::string> Objects;
   std::set<cmSourceFile const*> ExplicitObjectName;
 
+  using TargetPtrToBoolMap = std::unordered_map<cmTarget*, bool>;
+  mutable std::unordered_map<std::string, TargetPtrToBoolMap>
+    MacOSXRpathInstallNameDirCache;
+  bool DetermineHasMacOSXRpathInstallNameDir(const std::string& config) const;
+
   // "config/language" is the key
   mutable std::map<std::string, std::vector<std::string>> SystemIncludesCache;
 
@@ -877,12 +884,12 @@ private:
 
   bool NeedImportLibraryName(std::string const& config) const;
 
-  cmProp GetFilePrefixInternal(std::string const& config,
-                               cmStateEnums::ArtifactType artifact,
-                               const std::string& language = "") const;
-  cmProp GetFileSuffixInternal(std::string const& config,
-                               cmStateEnums::ArtifactType artifact,
-                               const std::string& language = "") const;
+  cmValue GetFilePrefixInternal(std::string const& config,
+                                cmStateEnums::ArtifactType artifact,
+                                const std::string& language = "") const;
+  cmValue GetFileSuffixInternal(std::string const& config,
+                                cmStateEnums::ArtifactType artifact,
+                                const std::string& language = "") const;
 
   std::string GetFullNameInternal(const std::string& config,
                                   cmStateEnums::ArtifactType artifact) const;
@@ -901,8 +908,7 @@ private:
 
   void ComputeVersionedName(std::string& vName, std::string const& prefix,
                             std::string const& base, std::string const& suffix,
-                            std::string const& name,
-                            const char* version) const;
+                            std::string const& name, cmValue version) const;
 
   struct CompatibleInterfacesBase
   {
@@ -1037,11 +1043,8 @@ private:
                        std::string const& config,
                        const cmGeneratorTarget* headTarget,
                        bool usage_requirements_only,
-                       std::vector<cmLinkItem>& items,
-                       std::vector<cmLinkItem>& objects,
-                       bool& hadHeadSensitiveCondition,
-                       bool& hadContextSensitiveCondition,
-                       bool& hadLinkLanguageSensitiveCondition) const;
+                       cmLinkInterface& iface) const;
+
   struct LookupLinkItemScope
   {
     cmLocalGenerator const* LG;
@@ -1113,8 +1116,8 @@ private:
 
   mutable std::map<std::string, BTs<std::string>> LanguageStandardMap;
 
-  cmProp GetPropertyWithPairedLanguageSupport(std::string const& lang,
-                                              const char* suffix) const;
+  cmValue GetPropertyWithPairedLanguageSupport(std::string const& lang,
+                                               const char* suffix) const;
 
   void ComputeLinkImplementationRuntimeLibraries(
     const std::string& config, cmOptionalLinkImplementation& impl) const;
index 79cbe44..42bd206 100644 (file)
@@ -7,9 +7,9 @@
 #include "cmExecutionStatus.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
+#include "cmValue.h"
 
 // cmGetCMakePropertyCommand
 bool cmGetCMakePropertyCommand(std::vector<std::string> const& args,
@@ -24,12 +24,12 @@ bool cmGetCMakePropertyCommand(std::vector<std::string> const& args,
   std::string output = "NOTFOUND";
 
   if (args[1] == "VARIABLES") {
-    if (cmProp varsProp = status.GetMakefile().GetProperty("VARIABLES")) {
+    if (cmValue varsProp = status.GetMakefile().GetProperty("VARIABLES")) {
       output = *varsProp;
     }
   } else if (args[1] == "MACROS") {
     output.clear();
-    if (cmProp macrosProp = status.GetMakefile().GetProperty("MACROS")) {
+    if (cmValue macrosProp = status.GetMakefile().GetProperty("MACROS")) {
       output = *macrosProp;
     }
   } else if (args[1] == "COMPONENTS") {
@@ -37,7 +37,7 @@ bool cmGetCMakePropertyCommand(std::vector<std::string> const& args,
       status.GetMakefile().GetGlobalGenerator()->GetInstallComponents();
     output = cmJoin(*components, ";");
   } else {
-    cmProp prop = nullptr;
+    cmValue prop = nullptr;
     if (!args[1].empty()) {
       prop = status.GetMakefile().GetState()->GetGlobalProperty(args[1]);
     }
index 7fbd479..d892cfa 100644 (file)
@@ -7,12 +7,14 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 namespace {
 void StoreResult(cmMakefile& makefile, std::string const& variable,
                  const char* prop);
+void StoreResult(cmMakefile& makefile, std::string const& variable,
+                 cmValue prop);
 }
 
 // cmGetDirectoryPropertyCommand
@@ -76,7 +78,6 @@ bool cmGetDirectoryPropertyCommand(std::vector<std::string> const& args,
     return false;
   }
 
-  const char* prop = nullptr;
   if (*i == "DEFINITIONS") {
     switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0059)) {
       case cmPolicies::WARN:
@@ -94,8 +95,7 @@ bool cmGetDirectoryPropertyCommand(std::vector<std::string> const& args,
         break;
     }
   }
-  prop = cmToCStr(dir->GetProperty(*i));
-  StoreResult(status.GetMakefile(), variable, prop);
+  StoreResult(status.GetMakefile(), variable, dir->GetProperty(*i));
   return true;
 }
 
@@ -105,4 +105,9 @@ void StoreResult(cmMakefile& makefile, std::string const& variable,
 {
   makefile.AddDefinition(variable, prop ? prop : "");
 }
+void StoreResult(cmMakefile& makefile, std::string const& variable,
+                 cmValue prop)
+{
+  makefile.AddDefinition(variable, prop);
+}
 }
index 40e8a05..abe7d32 100644 (file)
@@ -4,10 +4,10 @@
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 // cmGetFilenameComponentCommand
 bool cmGetFilenameComponentCommand(std::vector<std::string> const& args,
@@ -22,7 +22,7 @@ bool cmGetFilenameComponentCommand(std::vector<std::string> const& args,
   // Check and see if the value has been stored in the cache
   // already, if so use that value
   if (args.size() >= 4 && args.back() == "CACHE") {
-    cmProp cacheValue = status.GetMakefile().GetDefinition(args.front());
+    cmValue cacheValue = status.GetMakefile().GetDefinition(args.front());
     if (cacheValue && !cmIsNOTFOUND(*cacheValue)) {
       return true;
     }
index cb657f9..162860a 100644 (file)
@@ -2,6 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGetPropertyCommand.h"
 
+#include <cstddef>
+
 #include "cmExecutionStatus.h"
 #include "cmGlobalGenerator.h"
 #include "cmInstalledFile.h"
@@ -18,6 +20,7 @@
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTest.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 class cmMessenger;
@@ -32,10 +35,6 @@ enum OutType
   OutSet
 };
 
-// Implementation of result storage.
-bool StoreResult(OutType infoType, cmMakefile& makefile,
-                 const std::string& variable, const char* value);
-
 // Implementation of each property type.
 bool HandleGlobalMode(cmExecutionStatus& status, const std::string& name,
                       OutType infoType, const std::string& variable,
@@ -253,8 +252,10 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args,
 
 namespace {
 
+// Implementation of result storage.
+template <typename ValueType>
 bool StoreResult(OutType infoType, cmMakefile& makefile,
-                 const std::string& variable, const char* value)
+                 const std::string& variable, ValueType value)
 {
   if (infoType == OutSet) {
     makefile.AddDefinition(variable, value ? "1" : "0");
@@ -268,6 +269,12 @@ bool StoreResult(OutType infoType, cmMakefile& makefile,
   }
   return true;
 }
+template <>
+bool StoreResult(OutType infoType, cmMakefile& makefile,
+                 const std::string& variable, std::nullptr_t value)
+{
+  return StoreResult(infoType, makefile, variable, cmValue(value));
+}
 
 bool HandleGlobalMode(cmExecutionStatus& status, const std::string& name,
                       OutType infoType, const std::string& variable,
@@ -280,9 +287,8 @@ bool HandleGlobalMode(cmExecutionStatus& status, const std::string& name,
 
   // Get the property.
   cmake* cm = status.GetMakefile().GetCMakeInstance();
-  return StoreResult(
-    infoType, status.GetMakefile(), variable,
-    cmToCStr(cm->GetState()->GetGlobalProperty(propertyName)));
+  return StoreResult(infoType, status.GetMakefile(), variable,
+                     cm->GetState()->GetGlobalProperty(propertyName));
 }
 
 bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name,
@@ -329,7 +335,7 @@ bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name,
 
   // Get the property.
   return StoreResult(infoType, status.GetMakefile(), variable,
-                     cmToCStr(mf->GetProperty(propertyName)));
+                     mf->GetProperty(propertyName));
 }
 
 bool HandleTargetMode(cmExecutionStatus& status, const std::string& name,
@@ -361,12 +367,11 @@ bool HandleTargetMode(cmExecutionStatus& status, const std::string& name,
     }
     cmListFileBacktrace bt = status.GetMakefile().GetBacktrace();
     cmMessenger* messenger = status.GetMakefile().GetMessenger();
-    cmProp prop = target->GetComputedProperty(propertyName, messenger, bt);
+    cmValue prop = target->GetComputedProperty(propertyName, messenger, bt);
     if (!prop) {
       prop = target->GetProperty(propertyName);
     }
-    return StoreResult(infoType, status.GetMakefile(), variable,
-                       cmToCStr(prop));
+    return StoreResult(infoType, status.GetMakefile(), variable, prop);
   }
   status.SetError(cmStrCat("could not find TARGET ", name,
                            ".  Perhaps it has not yet been created."));
@@ -391,7 +396,7 @@ bool HandleSourceMode(cmExecutionStatus& status, const std::string& name,
   if (cmSourceFile* sf =
         directory_makefile.GetOrCreateSource(source_file_absolute_path)) {
     return StoreResult(infoType, status.GetMakefile(), variable,
-                       cmToCStr(sf->GetPropertyForUser(propertyName)));
+                       sf->GetPropertyForUser(propertyName));
   }
   status.SetError(
     cmStrCat("given SOURCE name that could not be found or created: ",
@@ -428,9 +433,8 @@ bool HandleVariableMode(cmExecutionStatus& status, const std::string& name,
     return false;
   }
 
-  return StoreResult(
-    infoType, status.GetMakefile(), variable,
-    cmToCStr(status.GetMakefile().GetDefinition(propertyName)));
+  return StoreResult(infoType, status.GetMakefile(), variable,
+                     status.GetMakefile().GetDefinition(propertyName));
 }
 
 bool HandleCacheMode(cmExecutionStatus& status, const std::string& name,
@@ -442,12 +446,12 @@ bool HandleCacheMode(cmExecutionStatus& status, const std::string& name,
     return false;
   }
 
-  cmProp value = nullptr;
+  cmValue value = nullptr;
   if (status.GetMakefile().GetState()->GetCacheEntryValue(name)) {
     value = status.GetMakefile().GetState()->GetCacheEntryProperty(
       name, propertyName);
   }
-  StoreResult(infoType, status.GetMakefile(), variable, cmToCStr(value));
+  StoreResult(infoType, status.GetMakefile(), variable, value);
   return true;
 }
 
index 5301b66..40ae112 100644 (file)
@@ -4,9 +4,9 @@
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmSetPropertyCommand.h"
 #include "cmSourceFile.h"
+#include "cmValue.h"
 
 bool cmGetSourceFilePropertyCommand(std::vector<std::string> const& args,
                                     cmExecutionStatus& status)
@@ -58,7 +58,7 @@ bool cmGetSourceFilePropertyCommand(std::vector<std::string> const& args,
   }
 
   if (sf) {
-    cmProp prop = nullptr;
+    cmValue prop = nullptr;
     if (!args[property_arg_index].empty()) {
       prop = sf->GetPropertyForUser(args[property_arg_index]);
     }
index 78a17d2..12c8221 100644 (file)
@@ -10,8 +10,8 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 
 class cmMessenger;
 
@@ -42,7 +42,7 @@ bool cmGetTargetPropertyCommand(std::vector<std::string> const& args,
         }
       }
     } else if (!args[2].empty()) {
-      cmProp prop_cstr = nullptr;
+      cmValue prop_cstr = nullptr;
       cmListFileBacktrace bt = mf.GetBacktrace();
       cmMessenger* messenger = mf.GetMessenger();
       prop_cstr = tgt->GetComputedProperty(args[2], messenger, bt);
@@ -62,6 +62,7 @@ bool cmGetTargetPropertyCommand(std::vector<std::string> const& args,
       case cmPolicies::WARN:
         issueMessage = true;
         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0045) << "\n";
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         break;
       case cmPolicies::REQUIRED_IF_USED:
@@ -69,6 +70,7 @@ bool cmGetTargetPropertyCommand(std::vector<std::string> const& args,
       case cmPolicies::NEW:
         issueMessage = true;
         messageType = MessageType::FATAL_ERROR;
+        break;
     }
     if (issueMessage) {
       e << "get_target_property() called with non-existent target \""
index cf8c1d5..a4ac9f6 100644 (file)
@@ -5,6 +5,7 @@
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmTest.h"
+#include "cmValue.h"
 
 bool cmGetTestPropertyCommand(std::vector<std::string> const& args,
                               cmExecutionStatus& status)
@@ -19,12 +20,12 @@ bool cmGetTestPropertyCommand(std::vector<std::string> const& args,
   cmMakefile& mf = status.GetMakefile();
   cmTest* test = mf.GetTest(testName);
   if (test) {
-    const char* prop = nullptr;
+    cmValue prop;
     if (!args[1].empty()) {
       prop = test->GetProperty(args[1]);
     }
     if (prop) {
-      mf.AddDefinition(var, prop);
+      mf.AddDefinition(var, prop->c_str());
       return true;
     }
   }
index 32238e4..47cefae 100644 (file)
@@ -19,7 +19,6 @@
 #include "cmLocalGhsMultiGenerator.h"
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
-#include "cmProperty.h"
 #include "cmSourceFile.h"
 #include "cmSourceFileLocation.h"
 #include "cmSourceGroup.h"
@@ -29,6 +28,7 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 
 cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
   : GeneratorTarget(target)
@@ -43,7 +43,7 @@ cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
 #endif
 {
   // Store the configuration name that is being used
-  if (cmProp config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
+  if (cmValue config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
     // Use the build type given by the user.
     this->ConfigName = *config;
   } else {
@@ -376,7 +376,7 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
 #ifdef _WIN32
   std::string check_error = "if %errorlevel% neq 0 exit /b %errorlevel%";
 #else
-  std::string check_error = "if [[ $? -ne 0 ]]; then exit 1; fi";
+  std::string check_error = "if [ $? -ne 0 ]; then exit 1; fi";
 #endif
 
 #ifdef _WIN32
@@ -453,7 +453,7 @@ void cmGhsMultiTargetGenerator::WriteSourceProperty(
   std::ostream& fout, const cmSourceFile* sf, std::string const& propName,
   std::string const& propFlag)
 {
-  cmProp prop = sf->GetProperty(propName);
+  cmValue prop = sf->GetProperty(propName);
   if (prop) {
     std::vector<std::string> list = cmExpandedList(*prop);
     for (const std::string& p : list) {
@@ -705,7 +705,7 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandLine(
 void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
   std::ostream& fout, const cmSourceFile* sourceFile)
 {
-  cmProp rawLangProp = sourceFile->GetProperty("LANGUAGE");
+  cmValue rawLangProp = sourceFile->GetProperty("LANGUAGE");
   if (rawLangProp) {
     std::string sourceLangProp(*rawLangProp);
     std::string const& extension = sourceFile->GetExtension();
@@ -717,7 +717,7 @@ void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
 
 bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()
 {
-  if (cmProp p = this->GeneratorTarget->GetProperty("ghs_integrity_app")) {
+  if (cmValue p = this->GeneratorTarget->GetProperty("ghs_integrity_app")) {
     return cmIsOn(*p);
   }
   std::vector<cmSourceFile*> sources;
index 9e5bbca..3ae66f0 100644 (file)
 #include "cmGeneratorTarget.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
-#include "cmStringAlgorithms.h"
-
-class cmake;
+#include "cmSystemTools.h"
+#include "cmValue.h"
+#include "cmake.h"
 
 cmGlobalCommonGenerator::cmGlobalCommonGenerator(cmake* cm)
   : cmGlobalGenerator(cm)
@@ -48,7 +47,7 @@ cmGlobalCommonGenerator::ComputeDirectoryTargets() const
       DirectoryTarget::Target t;
       t.GT = gt.get();
       const std::string EXCLUDE_FROM_ALL("EXCLUDE_FROM_ALL");
-      if (cmProp exclude = gt->GetProperty(EXCLUDE_FROM_ALL)) {
+      if (cmValue exclude = gt->GetProperty(EXCLUDE_FROM_ALL)) {
         for (const std::string& config : configs) {
           cmGeneratorExpressionInterpreter genexInterpreter(lg.get(), config,
                                                             gt.get());
@@ -95,3 +94,33 @@ bool cmGlobalCommonGenerator::IsExcludedFromAllInConfig(
   }
   return !t.ExcludedFromAllInConfigs.empty();
 }
+
+std::string cmGlobalCommonGenerator::GetEditCacheCommand() const
+{
+  // If generating for an extra IDE, the edit_cache target cannot
+  // launch a terminal-interactive tool, so always use cmake-gui.
+  if (!this->GetExtraGeneratorName().empty()) {
+    return cmSystemTools::GetCMakeGUICommand();
+  }
+
+  // Use an internal cache entry to track the latest dialog used
+  // to edit the cache, and use that for the edit_cache target.
+  cmake* cm = this->GetCMakeInstance();
+  std::string editCacheCommand = cm->GetCMakeEditCommand();
+  if (!cm->GetCacheDefinition("CMAKE_EDIT_COMMAND") ||
+      !editCacheCommand.empty()) {
+    if (this->SupportsDirectConsole() && editCacheCommand.empty()) {
+      editCacheCommand = cmSystemTools::GetCMakeCursesCommand();
+    }
+    if (editCacheCommand.empty()) {
+      editCacheCommand = cmSystemTools::GetCMakeGUICommand();
+    }
+    if (!editCacheCommand.empty()) {
+      cm->AddCacheEntry("CMAKE_EDIT_COMMAND", editCacheCommand,
+                        "Path to cache edit program executable.",
+                        cmStateEnums::INTERNAL);
+    }
+  }
+  cmValue edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND");
+  return edit_cmd ? *edit_cmd : std::string();
+}
index 2aa9d27..fed9ce8 100644 (file)
@@ -42,4 +42,9 @@ public:
   std::map<std::string, DirectoryTarget> ComputeDirectoryTargets() const;
   bool IsExcludedFromAllInConfig(const DirectoryTarget::Target& t,
                                  const std::string& config);
+
+protected:
+  virtual bool SupportsDirectConsole() const { return true; }
+  const char* GetEditCacheTargetName() const override { return "edit_cache"; }
+  std::string GetEditCacheCommand() const override;
 };
index 9193778..9914902 100644 (file)
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStateTypes.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 #include "cmWorkingDirectory.h"
 #include "cmake.h"
@@ -199,7 +199,7 @@ std::string cmGlobalGenerator::SelectMakeProgram(
 {
   std::string makeProgram = inMakeProgram;
   if (cmIsOff(makeProgram)) {
-    cmProp makeProgramCSTR =
+    cmValue makeProgramCSTR =
       this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
     if (cmIsOff(makeProgramCSTR)) {
       makeProgram = makeDefault;
@@ -235,14 +235,14 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang,
   if (!optional && (path.empty() || !cmSystemTools::FileExists(path))) {
     return;
   }
-  cmProp cname =
+  cmValue cname =
     this->GetCMakeInstance()->GetState()->GetInitializedCacheValue(langComp);
 
   // Split compiler from arguments
   std::vector<std::string> cnameArgVec;
   if (cname && !cname->empty()) {
     cmExpandList(*cname, cnameArgVec);
-    cname = &cnameArgVec.front();
+    cname = cmValue(cnameArgVec.front());
   }
 
   std::string changeVars;
@@ -258,7 +258,7 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang,
     cmSystemTools::ConvertToUnixSlashes(cnameString);
     cmSystemTools::ConvertToUnixSlashes(pathString);
     if (cnameString != pathString) {
-      cmProp cvars = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+      cmValue cvars = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
         "__CMAKE_DELETE_CACHE_CHANGE_VARS_");
       if (cvars) {
         changeVars += *cvars;
@@ -498,6 +498,18 @@ bool cmGlobalGenerator::CheckLanguages(
 void cmGlobalGenerator::EnableLanguage(
   std::vector<std::string> const& languages, cmMakefile* mf, bool optional)
 {
+  if (!this->IsMultiConfig()) {
+    std::string envBuildType;
+    if (!mf->GetDefinition("CMAKE_BUILD_TYPE") &&
+        cmSystemTools::GetEnv("CMAKE_BUILD_TYPE", envBuildType)) {
+      mf->AddCacheDefinition(
+        "CMAKE_BUILD_TYPE", envBuildType,
+        "Choose the type of build.  Options include: empty, "
+        "Debug, Release, RelWithDebInfo, MinSizeRel.",
+        cmStateEnums::STRING);
+    }
+  }
+
   if (languages.empty()) {
     cmSystemTools::Error("EnableLanguage must have a lang specified!");
     cmSystemTools::SetFatalErrorOccured();
@@ -581,16 +593,6 @@ void cmGlobalGenerator::EnableLanguage(
     }
   }
 
-  if (readCMakeSystem) {
-    // Find the native build tool for this generator.
-    // This has to be done early so that MSBuild can be used to examine the
-    // cross-compilation environment.
-    if (this->GetFindMakeProgramStage() == FindMakeProgramStage::Early &&
-        !this->FindMakeProgram(mf)) {
-      return;
-    }
-  }
-
   //  Load the CMakeDetermineSystem.cmake file and find out
   // what platform we are running on
   if (!mf->GetDefinition("CMAKE_SYSTEM")) {
@@ -664,8 +666,7 @@ void cmGlobalGenerator::EnableLanguage(
     }
 
     // Find the native build tool for this generator.
-    if (this->GetFindMakeProgramStage() == FindMakeProgramStage::Late &&
-        !this->FindMakeProgram(mf)) {
+    if (!this->FindMakeProgram(mf)) {
       return;
     }
   }
@@ -789,7 +790,7 @@ void cmGlobalGenerator::EnableLanguage(
     std::string compilerName = cmStrCat("CMAKE_", lang, "_COMPILER");
     std::string compilerEnv = cmStrCat("CMAKE_", lang, "_COMPILER_ENV_VAR");
     std::ostringstream noCompiler;
-    cmProp compilerFile = mf->GetDefinition(compilerName);
+    cmValue compilerFile = mf->GetDefinition(compilerName);
     if (!cmNonempty(compilerFile) || cmIsNOTFOUND(*compilerFile)) {
       /* clang-format off */
       noCompiler <<
@@ -826,7 +827,7 @@ void cmGlobalGenerator::EnableLanguage(
         cmSystemTools::RemoveFile(compilerLangFile);
         if (!this->CMakeInstance->GetIsInTryCompile()) {
           this->PrintCompilerAdvice(noCompiler, lang,
-                                    cmToCStr(mf->GetDefinition(compilerEnv)));
+                                    mf->GetDefinition(compilerEnv));
           mf->IssueMessage(MessageType::FATAL_ERROR, noCompiler.str());
           fatalError = true;
         }
@@ -910,7 +911,7 @@ void cmGlobalGenerator::EnableLanguage(
 
 void cmGlobalGenerator::PrintCompilerAdvice(std::ostream& os,
                                             std::string const& lang,
-                                            const char* envVar) const
+                                            cmValue envVar) const
 {
   // Subclasses override this method if they do not support this advice.
   os << "Tell CMake where to find the compiler by setting ";
@@ -953,6 +954,7 @@ void cmGlobalGenerator::CheckCompilerIdCompatibility(
         mf->IssueMessage(
           MessageType::FATAL_ERROR,
           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0025));
+        break;
       case cmPolicies::NEW:
         // NEW behavior is to keep AppleClang.
         break;
@@ -1019,6 +1021,7 @@ void cmGlobalGenerator::CheckCompilerIdCompatibility(
         mf->IssueMessage(
           MessageType::FATAL_ERROR,
           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0089));
+        break;
       case cmPolicies::NEW:
         // NEW behavior is to keep AppleClang.
         break;
@@ -1105,7 +1108,7 @@ void cmGlobalGenerator::SetLanguageEnabledMaps(const std::string& l,
   }
 
   std::string linkerPrefVar = "CMAKE_" + l + "_LINKER_PREFERENCE";
-  cmProp linkerPref = mf->GetDefinition(linkerPrefVar);
+  cmValue linkerPref = mf->GetDefinition(linkerPrefVar);
   int preference = 0;
   if (cmNonempty(linkerPref)) {
     if (sscanf(linkerPref->c_str(), "%d", &preference) != 1) {
@@ -1131,7 +1134,7 @@ void cmGlobalGenerator::SetLanguageEnabledMaps(const std::string& l,
   this->LanguageToLinkerPreference[l] = preference;
 
   std::string outputExtensionVar = "CMAKE_" + l + "_OUTPUT_EXTENSION";
-  if (cmProp p = mf->GetDefinition(outputExtensionVar)) {
+  if (cmValue p = mf->GetDefinition(outputExtensionVar)) {
     std::string outputExtension = *p;
     this->LanguageToOutputExtension[l] = outputExtension;
     this->OutputExtensions[outputExtension] = outputExtension;
@@ -1167,10 +1170,10 @@ void cmGlobalGenerator::FillExtensionToLanguageMap(const std::string& l,
   }
 }
 
-const char* cmGlobalGenerator::GetGlobalSetting(std::string const& name) const
+cmValue cmGlobalGenerator::GetGlobalSetting(std::string const& name) const
 {
   assert(!this->Makefiles.empty());
-  return cmToCStr(this->Makefiles[0]->GetDefinition(name));
+  return this->Makefiles[0]->GetDefinition(name);
 }
 
 bool cmGlobalGenerator::GlobalSettingIsOn(std::string const& name) const
@@ -1183,7 +1186,7 @@ std::string cmGlobalGenerator::GetSafeGlobalSetting(
   std::string const& name) const
 {
   assert(!this->Makefiles.empty());
-  return this->Makefiles[0]->GetSafeDefinition(name);
+  return this->Makefiles[0]->GetDefinition(name);
 }
 
 bool cmGlobalGenerator::IgnoreFile(const char* ext) const
@@ -1251,10 +1254,8 @@ void cmGlobalGenerator::Configure()
     this->CreateDefaultGlobalTargets(globalTargets);
 
     for (const auto& mf : this->Makefiles) {
-      auto& targets = mf->GetTargets();
       for (GlobalTargetInfo const& globalTarget : globalTargets) {
-        targets.emplace(globalTarget.Name,
-                        this->CreateGlobalTarget(globalTarget, mf.get()));
+        this->CreateGlobalTarget(globalTarget, mf.get());
       }
     }
   }
@@ -1401,6 +1402,9 @@ bool cmGlobalGenerator::Compute()
                                          this->SupportsDefaultConfigs())) {
     return false;
   }
+  if (!this->InspectConfigTypeVariables()) {
+    return false;
+  }
 
   // Some generators track files replaced during the Generate.
   // Start with an empty vector:
@@ -1708,10 +1712,8 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo()
 
   // Construct per-target generator information.
   for (const auto& mf : this->Makefiles) {
-    const cmStringRange noconfig_compile_definitions =
+    const cmBTStringRange noconfig_compile_definitions =
       mf->GetCompileDefinitionsEntries();
-    const cmBacktraceRange noconfig_compile_definitions_bts =
-      mf->GetCompileDefinitionsBacktraces();
 
     for (auto& target : mf->GetTargets()) {
       cmTarget* t = &target.second;
@@ -1725,12 +1727,8 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo()
         continue;
       }
 
-      {
-        auto btIt = noconfig_compile_definitions_bts.begin();
-        auto it = noconfig_compile_definitions.begin();
-        for (; it != noconfig_compile_definitions.end(); ++it, ++btIt) {
-          t->InsertCompileDefinition(*it, *btIt);
-        }
+      for (auto const& def : noconfig_compile_definitions) {
+        t->InsertCompileDefinition(def);
       }
 
       cmPolicies::PolicyStatus polSt =
@@ -1742,7 +1740,7 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo()
         for (std::string const& c : configs) {
           std::string defPropName =
             cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(c));
-          if (cmProp val = mf->GetProperty(defPropName)) {
+          if (cmValue val = mf->GetProperty(defPropName)) {
             t->AppendProperty(defPropName, *val);
           }
         }
@@ -1771,9 +1769,8 @@ void cmGlobalGenerator::CreateGeneratorTargets(
   std::map<cmTarget*, cmGeneratorTarget*> const& importedMap)
 {
   if (targetTypes == AllTargets) {
-    for (auto& target : mf->GetTargets()) {
-      cmTarget* t = &target.second;
-      lg->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(t, lg));
+    for (cmTarget* target : mf->GetOrderedTargets()) {
+      lg->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(target, lg));
     }
   }
 
@@ -1857,7 +1854,7 @@ void cmGlobalGenerator::CheckTargetProperties()
         }
       }
       std::vector<std::string> incs;
-      cmProp incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES");
+      cmValue incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES");
       if (!incDirProp) {
         continue;
       }
@@ -2121,7 +2118,7 @@ void cmGlobalGenerator::AddMakefile(std::unique_ptr<cmMakefile> mf)
 
   // update progress
   // estimate how many lg there will be
-  cmProp numGenC = this->CMakeInstance->GetState()->GetInitializedCacheValue(
+  cmValue numGenC = this->CMakeInstance->GetState()->GetInitializedCacheValue(
     "CMAKE_NUMBER_OF_MAKEFILES");
 
   if (!numGenC) {
@@ -2180,11 +2177,10 @@ void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator* gen,
 {
   this->SetConfiguredFilesPath(gen);
   this->TryCompileOuterMakefile = mf;
-  cmProp make =
+  cmValue make =
     gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
-  this->GetCMakeInstance()->AddCacheEntry("CMAKE_MAKE_PROGRAM", cmToCStr(make),
-                                          "make program",
-                                          cmStateEnums::FILEPATH);
+  this->GetCMakeInstance()->AddCacheEntry(
+    "CMAKE_MAKE_PROGRAM", make, "make program", cmStateEnums::FILEPATH);
   // copy the enabled languages
   this->GetCMakeInstance()->GetState()->SetEnabledLanguages(
     gen->GetCMakeInstance()->GetState()->GetEnabledLanguages());
@@ -2244,7 +2240,7 @@ bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
   }
   cmMakefile* mf = root->GetMakefile();
   const std::string EXCLUDE_FROM_ALL = "EXCLUDE_FROM_ALL";
-  if (cmProp exclude = target->GetProperty(EXCLUDE_FROM_ALL)) {
+  if (cmValue exclude = target->GetProperty(EXCLUDE_FROM_ALL)) {
     // Expand the property value per configuration.
     unsigned int trueCount = 0;
     unsigned int falseCount = 0;
@@ -2538,7 +2534,7 @@ void cmGlobalGenerator::AddGlobalTarget_Package(
   if (this->GetPreinstallTargetName()) {
     gti.Depends.emplace_back(this->GetPreinstallTargetName());
   } else {
-    cmProp noPackageAll =
+    cmValue noPackageAll =
       mf->GetDefinition("CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY");
     if (cmIsOff(noPackageAll)) {
       gti.Depends.emplace_back(this->GetAllTargetName());
@@ -2719,7 +2715,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install(
     if (this->GetPreinstallTargetName()) {
       gti.Depends.emplace_back(this->GetPreinstallTargetName());
     } else {
-      cmProp noall = mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
+      cmValue noall = mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
       if (cmIsOff(noall)) {
         gti.Depends.emplace_back(this->GetAllTargetName());
       }
@@ -2740,7 +2736,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install(
         singleLine.push_back(cfgArg);
         cfgArg = "-DEFFECTIVE_PLATFORM_NAME=$(EFFECTIVE_PLATFORM_NAME)";
       } else {
-        cfgArg += cmToCStr(mf->GetDefinition("CMAKE_CFG_INTDIR"));
+        cfgArg += *mf->GetDefinition("CMAKE_CFG_INTDIR");
       }
       singleLine.push_back(cfgArg);
     }
@@ -2785,7 +2781,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install(
 
 std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
 {
-  cmProp prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+  cmValue prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
     "PREDEFINED_TARGETS_FOLDER");
 
   if (prop) {
@@ -2797,7 +2793,7 @@ std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
 
 bool cmGlobalGenerator::UseFolderProperty() const
 {
-  cmProp prop =
+  cmValue prop =
     this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS");
 
   // If this property is defined, let the setter turn this on or off...
@@ -2812,12 +2808,19 @@ bool cmGlobalGenerator::UseFolderProperty() const
   return false;
 }
 
-cmTarget cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti,
-                                               cmMakefile* mf)
+void cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti,
+                                           cmMakefile* mf)
 {
   // Package
-  cmTarget target(gti.Name, cmStateEnums::GLOBAL_TARGET,
-                  cmTarget::VisibilityNormal, mf, gti.PerConfig);
+  auto tb =
+    mf->CreateNewTarget(gti.Name, cmStateEnums::GLOBAL_TARGET, gti.PerConfig);
+
+  // Do nothing if gti.Name is already used
+  if (!tb.second) {
+    return;
+  }
+
+  cmTarget& target = tb.first;
   target.SetProperty("EXCLUDE_FROM_ALL", "TRUE");
 
   std::vector<std::string> no_outputs;
@@ -2841,8 +2844,6 @@ cmTarget cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti,
   if (this->UseFolderProperty()) {
     target.SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
   }
-
-  return target;
 }
 
 std::string cmGlobalGenerator::GenerateRuleFile(
@@ -3143,10 +3144,10 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
 
 #ifndef CMAKE_BOOTSTRAP
   // Check whether labels are enabled for this target.
-  cmProp targetLabels = target->GetProperty("LABELS");
-  cmProp directoryLabels =
+  cmValue targetLabels = target->GetProperty("LABELS");
+  cmValue directoryLabels =
     target->Target->GetMakefile()->GetProperty("LABELS");
-  cmProp cmakeDirectoryLabels =
+  cmValue cmakeDirectoryLabels =
     target->Target->GetMakefile()->GetDefinition("CMAKE_DIRECTORY_LABELS");
   if (targetLabels || directoryLabels || cmakeDirectoryLabels) {
     Json::Value lj_root(Json::objectValue);
@@ -3214,7 +3215,7 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
       std::string const& sfp = sf->ResolveFullPath();
       fout << sfp << "\n";
       lj_source["file"] = sfp;
-      if (cmProp svalue = sf->GetProperty("LABELS")) {
+      if (cmValue svalue = sf->GetProperty("LABELS")) {
         labels.clear();
         Json::Value& lj_source_labels = lj_source["labels"] = Json::arrayValue;
         cmExpandList(*svalue, labels);
index 147146e..96696aa 100644 (file)
@@ -29,6 +29,7 @@
 #include "cmTarget.h"
 #include "cmTargetDepend.h"
 #include "cmTransformDepfile.h"
+#include "cmValue.h"
 
 #if !defined(CMAKE_BOOTSTRAP)
 #  include <cm3p/json/value.h>
@@ -152,6 +153,8 @@ public:
    */
   virtual void Configure();
 
+  virtual bool InspectConfigTypeVariables() { return true; }
+
   bool Compute();
   virtual void AddExtraIDETargets() {}
 
@@ -308,7 +311,7 @@ public:
 
   cmExportSetMap& GetExportSets() { return this->ExportSets; }
 
-  const char* GetGlobalSetting(std::string const& name) const;
+  cmValue GetGlobalSetting(std::string const& name) const;
   bool GlobalSettingIsOn(std::string const& name) const;
   std::string GetSafeGlobalSetting(std::string const& name) const;
 
@@ -443,6 +446,8 @@ public:
 
   virtual bool IsVisualStudio() const { return false; }
 
+  virtual bool IsVisualStudioAtLeast10() const { return false; }
+
   virtual bool IsNinja() const { return false; }
 
   /** Return true if we know the exact location of object files.
@@ -549,7 +554,7 @@ protected:
   virtual bool CheckLanguages(std::vector<std::string> const& languages,
                               cmMakefile* mf) const;
   virtual void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
-                                   const char* envVar) const;
+                                   cmValue envVar) const;
 
   virtual bool ComputeTargetDepends();
 
@@ -596,7 +601,7 @@ protected:
   void AddGlobalTarget_RebuildCache(
     std::vector<GlobalTargetInfo>& targets) const;
   void AddGlobalTarget_Install(std::vector<GlobalTargetInfo>& targets);
-  cmTarget CreateGlobalTarget(GlobalTargetInfo const& gti, cmMakefile* mf);
+  void CreateGlobalTarget(GlobalTargetInfo const& gti, cmMakefile* mf);
 
   std::string FindMakeProgramFile;
   std::string ConfiguredFilesPath;
@@ -622,17 +627,6 @@ protected:
 
   std::string GetPredefinedTargetsFolder() const;
 
-  enum class FindMakeProgramStage
-  {
-    Early,
-    Late,
-  };
-
-  virtual FindMakeProgramStage GetFindMakeProgramStage() const
-  {
-    return FindMakeProgramStage::Late;
-  }
-
 private:
   using TargetMap = std::unordered_map<std::string, cmTarget*>;
   using GeneratorTargetMap =
index 7cf3e93..b1c0488 100644 (file)
 #include "cmLocalGenerator.h"
 #include "cmLocalGhsMultiGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 #include "cmake.h"
 
@@ -99,7 +99,7 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
   /* set the build tool to use */
   std::string gbuild(tsp + ((tsp.back() == '/') ? "" : "/") +
                      DEFAULT_BUILD_PROGRAM);
-  cmProp prevTool = mf->GetDefinition("CMAKE_MAKE_PROGRAM");
+  cmValue prevTool = mf->GetDefinition("CMAKE_MAKE_PROGRAM");
 
   /* check if the toolset changed from last generate */
   if (prevTool && (gbuild != *prevTool)) {
@@ -186,8 +186,7 @@ void cmGlobalGhsMultiGenerator::EnableLanguage(
 
   mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files
 
-  const char* tgtPlatform =
-    cmToCStrSafe(mf->GetDefinition("GHS_TARGET_PLATFORM"));
+  const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM")->c_str();
   if (!tgtPlatform) {
     cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not "
                            "specified; defaulting to \"integrity\"");
@@ -216,7 +215,7 @@ bool cmGlobalGhsMultiGenerator::FindMakeProgram(cmMakefile* /*mf*/)
 void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsd,
                                            const std::string& ts)
 {
-  cmProp ghsRoot = mf->GetDefinition("GHS_TOOLSET_ROOT");
+  cmValue ghsRoot = mf->GetDefinition("GHS_TOOLSET_ROOT");
 
   if (cmNonempty(ghsRoot)) {
     tsd = *ghsRoot;
@@ -334,7 +333,7 @@ void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout,
   fout << "# Top Level Project File\n";
 
   // Specify BSP option if supplied by user
-  cmProp bspName =
+  cmValue bspName =
     this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
   if (!cmIsOff(bspName)) {
     fout << "    -bsp " << *bspName << '\n';
@@ -343,7 +342,7 @@ void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout,
   // Specify OS DIR if supplied by user
   // -- not all platforms require this entry in the project file
   if (!cmIsOff(this->OsDir)) {
-    cmProp osDirOption =
+    cmValue osDirOption =
       this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION");
     std::replace(this->OsDir.begin(), this->OsDir.end(), '\\', '/');
     fout << "    ";
@@ -378,8 +377,8 @@ void cmGlobalGhsMultiGenerator::WriteProjectLine(
   std::ostream& fout, cmGeneratorTarget const* target,
   std::string& rootBinaryDir)
 {
-  cmProp projName = target->GetProperty("GENERATOR_FILE_NAME");
-  cmProp projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
+  cmValue projName = target->GetProperty("GENERATOR_FILE_NAME");
+  cmValue projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
   if (projName && projType) {
     cmLocalGenerator* lg = target->GetLocalGenerator();
     std::string dir = lg->GetCurrentBinaryDirectory();
@@ -564,7 +563,7 @@ cmGlobalGhsMultiGenerator::GenerateBuildCommand(
 {
   GeneratedMakeCommand makeCommand = {};
   std::string gbuild;
-  if (cmProp gbuildCached =
+  if (cmValue gbuildCached =
         this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM")) {
     gbuild = *gbuildCached;
   }
@@ -617,7 +616,7 @@ void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout,
                                             cmLocalGenerator* root)
 {
   fout << "macro PROJ_NAME=" << root->GetProjectName() << '\n';
-  cmProp ghsGpjMacros =
+  cmValue ghsGpjMacros =
     this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
   if (ghsGpjMacros) {
     std::vector<std::string> expandedList = cmExpandedList(*ghsGpjMacros);
@@ -632,15 +631,15 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(
 {
   /* set primary target */
   std::string tgt;
-  cmProp t =
+  cmValue t =
     this->GetCMakeInstance()->GetCacheDefinition("GHS_PRIMARY_TARGET");
   if (cmNonempty(t)) {
     tgt = *t;
     this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET");
   } else {
-    cmProp a =
+    cmValue a =
       this->GetCMakeInstance()->GetCacheDefinition("CMAKE_GENERATOR_PLATFORM");
-    cmProp p =
+    cmValue p =
       this->GetCMakeInstance()->GetCacheDefinition("GHS_TARGET_PLATFORM");
     tgt = cmStrCat((a ? *a : ""), '_', (p ? *p : ""), ".tgt");
   }
@@ -653,7 +652,7 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(
        << "/CMakeFiles/custom_target.bod" << '\n';
   /* clang-format on */
 
-  cmProp const customization =
+  cmValue const customization =
     this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
   if (cmNonempty(customization)) {
     fout << "customization="
index fc3123a..40deebb 100644 (file)
@@ -39,8 +39,9 @@ void cmGlobalJOMMakefileGenerator::GetDocumentation(
   entry.Brief = "Generates JOM makefiles.";
 }
 
-void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(
-  std::ostream& os, std::string const& lang, const char* envVar) const
+void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(std::ostream& os,
+                                                       std::string const& lang,
+                                                       cmValue envVar) const
 {
   if (lang == "CXX" || lang == "C") {
     /* clang-format off */
index 2d58f91..58860dd 100644 (file)
@@ -50,5 +50,5 @@ protected:
 
 private:
   void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
-                           const char* envVar) const override;
+                           cmValue envVar) const override;
 };
index f08b1da..a038f87 100644 (file)
@@ -42,7 +42,7 @@ bool cmGlobalNMakeMakefileGenerator::FindMakeProgram(cmMakefile* mf)
   if (!this->cmGlobalGenerator::FindMakeProgram(mf)) {
     return false;
   }
-  if (cmProp nmakeCommand = mf->GetDefinition("CMAKE_MAKE_PROGRAM")) {
+  if (cmValue nmakeCommand = mf->GetDefinition("CMAKE_MAKE_PROGRAM")) {
     std::vector<std::string> command{ *nmakeCommand, "-?" };
     std::string out;
     std::string err;
@@ -70,7 +70,7 @@ bool cmGlobalNMakeMakefileGenerator::FindMakeProgram(cmMakefile* mf)
 void cmGlobalNMakeMakefileGenerator::CheckNMakeFeatures()
 {
   this->NMakeSupportsUTF8 = !cmSystemTools::VersionCompare(
-    cmSystemTools::OP_LESS, this->NMakeVersion.c_str(), "9");
+    cmSystemTools::OP_LESS, this->NMakeVersion, "9");
 }
 
 void cmGlobalNMakeMakefileGenerator::GetDocumentation(
@@ -81,7 +81,7 @@ void cmGlobalNMakeMakefileGenerator::GetDocumentation(
 }
 
 void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice(
-  std::ostream& os, std::string const& lang, const char* envVar) const
+  std::ostream& os, std::string const& lang, cmValue envVar) const
 {
   if (lang == "CXX" || lang == "C") {
     /* clang-format off */
index 402b89f..4f202b5 100644 (file)
@@ -61,5 +61,5 @@ private:
   void CheckNMakeFeatures();
 
   void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
-                           const char* envVar) const override;
+                           cmValue envVar) const override;
 };
index 971a462..7122b9f 100644 (file)
@@ -35,7 +35,6 @@
 #include "cmMessageType.h"
 #include "cmNinjaLinkLineComputer.h"
 #include "cmOutputConverter.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmScanDepFormat.h"
 #include "cmState.h"
@@ -46,6 +45,7 @@
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTargetDepend.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 #include "cmake.h"
 
@@ -382,7 +382,7 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
     if (restat) {
       vars["restat"] = "1";
     }
-    if (uses_terminal && this->SupportsConsolePool()) {
+    if (uses_terminal && this->SupportsDirectConsole()) {
       vars["pool"] = "console";
     } else if (!job_pool.empty()) {
       vars["pool"] = job_pool;
@@ -558,9 +558,8 @@ void cmGlobalNinjaGenerator::GetDocumentation(cmDocumentationEntry& entry)
 void cmGlobalNinjaGenerator::Generate()
 {
   // Check minimum Ninja version.
-  if (cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
-                                    this->NinjaVersion.c_str(),
-                                    RequiredNinjaVersion().c_str())) {
+  if (cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, this->NinjaVersion,
+                                    RequiredNinjaVersion())) {
     std::ostringstream msg;
     msg << "The detected version of Ninja (" << this->NinjaVersion;
     msg << ") is less than the version of Ninja required by CMake (";
@@ -569,9 +568,6 @@ void cmGlobalNinjaGenerator::Generate()
                                            msg.str());
     return;
   }
-  if (!this->InspectConfigTypeVariables()) {
-    return;
-  }
   if (!this->OpenBuildFileStreams()) {
     return;
   }
@@ -695,7 +691,7 @@ bool cmGlobalNinjaGenerator::FindMakeProgram(cmMakefile* mf)
   if (!this->cmGlobalGenerator::FindMakeProgram(mf)) {
     return false;
   }
-  if (cmProp ninjaCommand = mf->GetDefinition("CMAKE_MAKE_PROGRAM")) {
+  if (cmValue ninjaCommand = mf->GetDefinition("CMAKE_MAKE_PROGRAM")) {
     this->NinjaCommand = *ninjaCommand;
     std::vector<std::string> command;
     command.push_back(this->NinjaCommand);
@@ -721,21 +717,21 @@ bool cmGlobalNinjaGenerator::FindMakeProgram(cmMakefile* mf)
 
 void cmGlobalNinjaGenerator::CheckNinjaFeatures()
 {
-  this->NinjaSupportsConsolePool = !cmSystemTools::VersionCompare(
-    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
-    RequiredNinjaVersionForConsolePool().c_str());
+  this->NinjaSupportsConsolePool =
+    !cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, this->NinjaVersion,
+                                   RequiredNinjaVersionForConsolePool());
   this->NinjaSupportsImplicitOuts = !cmSystemTools::VersionCompare(
-    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
-    cmGlobalNinjaGenerator::RequiredNinjaVersionForImplicitOuts().c_str());
-  this->NinjaSupportsManifestRestat = !cmSystemTools::VersionCompare(
-    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
-    RequiredNinjaVersionForManifestRestat().c_str());
-  this->NinjaSupportsMultilineDepfile = !cmSystemTools::VersionCompare(
-    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
-    RequiredNinjaVersionForMultilineDepfile().c_str());
-  this->NinjaSupportsDyndeps = !cmSystemTools::VersionCompare(
-    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
-    RequiredNinjaVersionForDyndeps().c_str());
+    cmSystemTools::OP_LESS, this->NinjaVersion,
+    cmGlobalNinjaGenerator::RequiredNinjaVersionForImplicitOuts());
+  this->NinjaSupportsManifestRestat =
+    !cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, this->NinjaVersion,
+                                   RequiredNinjaVersionForManifestRestat());
+  this->NinjaSupportsMultilineDepfile =
+    !cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, this->NinjaVersion,
+                                   RequiredNinjaVersionForMultilineDepfile());
+  this->NinjaSupportsDyndeps =
+    !cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, this->NinjaVersion,
+                                   RequiredNinjaVersionForDyndeps());
   if (!this->NinjaSupportsDyndeps) {
     // The ninja version number is not new enough to have upstream support.
     // Our ninja branch adds ".dyndep-#" to its version number,
@@ -753,21 +749,21 @@ void cmGlobalNinjaGenerator::CheckNinjaFeatures()
   }
   this->NinjaSupportsUnconditionalRecompactTool =
     !cmSystemTools::VersionCompare(
-      cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
-      RequiredNinjaVersionForUnconditionalRecompactTool().c_str());
-  this->NinjaSupportsRestatTool = !cmSystemTools::VersionCompare(
-    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
-    RequiredNinjaVersionForRestatTool().c_str());
-  this->NinjaSupportsMultipleOutputs = !cmSystemTools::VersionCompare(
-    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
-    RequiredNinjaVersionForMultipleOutputs().c_str());
+      cmSystemTools::OP_LESS, this->NinjaVersion,
+      RequiredNinjaVersionForUnconditionalRecompactTool());
+  this->NinjaSupportsRestatTool =
+    !cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, this->NinjaVersion,
+                                   RequiredNinjaVersionForRestatTool());
+  this->NinjaSupportsMultipleOutputs =
+    !cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, this->NinjaVersion,
+                                   RequiredNinjaVersionForMultipleOutputs());
   this->NinjaSupportsMetadataOnRegeneration = !cmSystemTools::VersionCompare(
-    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
-    RequiredNinjaVersionForMetadataOnRegeneration().c_str());
+    cmSystemTools::OP_LESS, this->NinjaVersion,
+    RequiredNinjaVersionForMetadataOnRegeneration());
 #ifdef _WIN32
-  this->NinjaSupportsCodePage = !cmSystemTools::VersionCompare(
-    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
-    RequiredNinjaVersionForCodePage().c_str());
+  this->NinjaSupportsCodePage =
+    !cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, this->NinjaVersion,
+                                   RequiredNinjaVersionForCodePage());
   if (this->NinjaSupportsCodePage) {
     this->CheckNinjaCodePage();
   } else {
@@ -920,14 +916,7 @@ void cmGlobalNinjaGenerator::EnableLanguage(
   std::vector<std::string> const& langs, cmMakefile* mf, bool optional)
 {
   if (this->IsMultiConfig()) {
-    if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
-      mf->AddCacheDefinition(
-        "CMAKE_CONFIGURATION_TYPES", "Debug;Release;RelWithDebInfo",
-        "Semicolon separated list of supported configuration types, only "
-        "supports Debug, Release, MinSizeRel, and RelWithDebInfo, anything "
-        "else will be ignored",
-        cmStateEnums::STRING);
-    }
+    mf->InitCMAKE_CONFIGURATION_TYPES("Debug;Release;RelWithDebInfo");
   }
 
   this->cmGlobalGenerator::EnableLanguage(langs, mf, optional);
@@ -936,29 +925,21 @@ void cmGlobalNinjaGenerator::EnableLanguage(
       continue;
     }
     this->ResolveLanguageCompiler(l, mf, optional);
-  }
 #ifdef _WIN32
-  const bool clangGnuMode =
-    ((mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "Clang") &&
-     (mf->GetSafeDefinition("CMAKE_C_COMPILER_FRONTEND_VARIANT") == "GNU")) ||
-    ((mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "Clang") &&
-     (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_FRONTEND_VARIANT") == "GNU"));
-
-  if (clangGnuMode ||
-      ((mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID") != "MSVC") &&
-       (mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID") != "MSVC") &&
-       (mf->IsOn("CMAKE_COMPILER_IS_MINGW") ||
-        (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "GNU") ||
-        (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "GNU") ||
-        (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "Clang") ||
-        (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "Clang") ||
-        (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "ARMClang") ||
-        (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "ARMClang") ||
-        (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "QCC") ||
-        (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "QCC")))) {
-    this->UsingGCCOnWindows = true;
-  }
+    std::string const& compilerId =
+      mf->GetSafeDefinition(cmStrCat("CMAKE_", l, "_COMPILER_ID"));
+    std::string const& simulateId =
+      mf->GetSafeDefinition(cmStrCat("CMAKE_", l, "_SIMULATE_ID"));
+    std::string const& compilerFrontendVariant = mf->GetSafeDefinition(
+      cmStrCat("CMAKE_", l, "_COMPILER_FRONTEND_VARIANT"));
+    if ((compilerId == "Clang" && compilerFrontendVariant == "GNU") ||
+        (simulateId != "MSVC" &&
+         (compilerId == "GNU" || compilerId == "QCC" ||
+          cmHasLiteralSuffix(compilerId, "Clang")))) {
+      this->UsingGCCOnWindows = true;
+    }
 #endif
+  }
 }
 
 // Implemented by:
@@ -1021,13 +1002,6 @@ bool cmGlobalNinjaGenerator::HasRule(const std::string& name)
 
 // Private virtual overrides
 
-std::string cmGlobalNinjaGenerator::GetEditCacheCommand() const
-{
-  // Ninja by design does not run interactive tools in the terminal,
-  // so our only choice is cmake-gui.
-  return cmSystemTools::GetCMakeGUICommand();
-}
-
 void cmGlobalNinjaGenerator::ComputeTargetObjectDirectory(
   cmGeneratorTarget* gt) const
 {
@@ -1286,7 +1260,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs(
         break;
       }
     }
-    // FALLTHROUGH
+      CM_FALLTHROUGH;
     case cmStateEnums::EXECUTABLE: {
       outputs.push_back(this->ConvertToNinjaPath(target->GetFullPath(
         config, cmStateEnums::RuntimeBinaryArtifact, realname)));
@@ -1298,7 +1272,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs(
         break;
       }
     }
-    // FALLTHROUGH
+      CM_FALLTHROUGH;
     case cmStateEnums::GLOBAL_TARGET:
     case cmStateEnums::INTERFACE_LIBRARY:
     case cmStateEnums::UTILITY: {
@@ -1849,7 +1823,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
 
   // Use 'console' pool to get non buffered output of the CMake re-run call
   // Available since Ninja 1.5
-  if (this->SupportsConsolePool()) {
+  if (this->SupportsDirectConsole()) {
     reBuild.Variables["pool"] = "console";
   }
 
@@ -1943,7 +1917,7 @@ std::string cmGlobalNinjaGenerator::NinjaCmd() const
   return "ninja";
 }
 
-bool cmGlobalNinjaGenerator::SupportsConsolePool() const
+bool cmGlobalNinjaGenerator::SupportsDirectConsole() const
 {
   return this->NinjaSupportsConsolePool;
 }
index bb4ce2b..84fc06c 100644 (file)
@@ -220,7 +220,6 @@ public:
   {
     return "package_source";
   }
-  const char* GetEditCacheTargetName() const override { return "edit_cache"; }
   const char* GetRebuildCacheTargetName() const override
   {
     return "rebuild_cache";
@@ -406,7 +405,7 @@ public:
     return "1.10.2";
   }
   static std::string RequiredNinjaVersionForCodePage() { return "1.11"; }
-  bool SupportsConsolePool() const;
+  bool SupportsDirectConsole() const override;
   bool SupportsImplicitOuts() const;
   bool SupportsManifestRestat() const;
   bool SupportsMultilineDepfile() const;
@@ -482,14 +481,11 @@ protected:
     const std::set<std::string>& all, const std::set<std::string>& defaults,
     const std::vector<std::string>& items);
 
-  virtual bool InspectConfigTypeVariables() { return true; }
-
   std::set<std::string> CrossConfigs;
   std::set<std::string> DefaultConfigs;
   std::string DefaultFileConfig;
 
 private:
-  std::string GetEditCacheCommand() const override;
   bool FindMakeProgram(cmMakefile* mf) override;
   void CheckNinjaFeatures();
   void CheckNinjaCodePage();
index 9c3de1e..0556540 100644 (file)
 #include "cmMakefile.h"
 #include "cmMakefileTargetGenerator.h"
 #include "cmOutputConverter.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTargetDepend.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm)
@@ -78,36 +78,6 @@ void cmGlobalUnixMakefileGenerator3::GetDocumentation(
   entry.Brief = "Generates standard UNIX makefiles.";
 }
 
-std::string cmGlobalUnixMakefileGenerator3::GetEditCacheCommand() const
-{
-  // If generating for an extra IDE, the edit_cache target cannot
-  // launch a terminal-interactive tool, so always use cmake-gui.
-  if (!this->GetExtraGeneratorName().empty()) {
-    return cmSystemTools::GetCMakeGUICommand();
-  }
-
-  // Use an internal cache entry to track the latest dialog used
-  // to edit the cache, and use that for the edit_cache target.
-  cmake* cm = this->GetCMakeInstance();
-  std::string editCacheCommand = cm->GetCMakeEditCommand();
-  if (!cm->GetCacheDefinition("CMAKE_EDIT_COMMAND") ||
-      !editCacheCommand.empty()) {
-    if (editCacheCommand.empty()) {
-      editCacheCommand = cmSystemTools::GetCMakeCursesCommand();
-    }
-    if (editCacheCommand.empty()) {
-      editCacheCommand = cmSystemTools::GetCMakeGUICommand();
-    }
-    if (!editCacheCommand.empty()) {
-      cm->AddCacheEntry("CMAKE_EDIT_COMMAND", editCacheCommand.c_str(),
-                        "Path to cache edit program executable.",
-                        cmStateEnums::INTERNAL);
-    }
-  }
-  cmProp edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND");
-  return edit_cmd ? *edit_cmd : std::string();
-}
-
 void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory(
   cmGeneratorTarget* gt) const
 {
@@ -714,7 +684,7 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
       }
 
       bool targetMessages = true;
-      if (cmProp tgtMsg =
+      if (cmValue tgtMsg =
             this->GetCMakeInstance()->GetState()->GetGlobalProperty(
               "TARGET_MESSAGES")) {
         targetMessages = cmIsOn(*tgtMsg);
index 7c950cc..94ee476 100644 (file)
@@ -228,7 +228,6 @@ protected:
   {
     return "package_source";
   }
-  const char* GetEditCacheTargetName() const override { return "edit_cache"; }
   const char* GetRebuildCacheTargetName() const override
   {
     return "rebuild_cache";
@@ -278,7 +277,6 @@ protected:
 
 private:
   const char* GetBuildIgnoreErrorsFlag() const override { return "-i"; }
-  std::string GetEditCacheCommand() const override;
 
   std::map<cmStateSnapshot, std::set<cmGeneratorTarget const*>,
            cmStateSnapshot::StrictWeakOrder>
index fdb7155..6cab492 100644 (file)
@@ -88,7 +88,7 @@ public:
   void GetDocumentation(cmDocumentationEntry& entry) const override
   {
     entry.Name = std::string(vs10generatorName) + " [arch]";
-    entry.Brief = "Generates Visual Studio 2010 project files.  "
+    entry.Brief = "Deprecated.  Generates Visual Studio 2010 project files.  "
                   "Optional [arch] can be \"Win64\" or \"IA64\".";
   }
 
@@ -139,7 +139,6 @@ cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator(
     "ProductDir",
     vc10Express, cmSystemTools::KeyWOW64_32);
   this->CudaEnabled = false;
-  this->MSBuildCommandInitialized = false;
   {
     std::string envPlatformToolset;
     if (cmSystemTools::GetEnv("PlatformToolset", envPlatformToolset) &&
@@ -581,6 +580,13 @@ bool cmGlobalVisualStudio10Generator::InitializeWindowsCE(cmMakefile* mf)
 
   this->DefaultPlatformToolset = this->SelectWindowsCEToolset();
 
+  if (this->GetVersion() == cmGlobalVisualStudioGenerator::VS12) {
+    // VS 12 .NET CF defaults to .NET framework 3.9 for Windows CE.
+    this->DefaultTargetFrameworkVersion = "v3.9";
+    this->DefaultTargetFrameworkIdentifier = "WindowsEmbeddedCompact";
+    this->DefaultTargetFrameworkTargetsVersion = "v8.0";
+  }
+
   return true;
 }
 
@@ -857,6 +863,12 @@ std::string const& cmGlobalVisualStudio10Generator::GetMSBuildCommand()
   return this->MSBuildCommand;
 }
 
+cm::optional<std::string>
+cmGlobalVisualStudio10Generator::FindMSBuildCommandEarly(cmMakefile*)
+{
+  return this->GetMSBuildCommand();
+}
+
 std::string cmGlobalVisualStudio10Generator::FindMSBuildCommand()
 {
   std::string msbuild;
index b7ae1ee..6e62390 100644 (file)
@@ -20,6 +20,8 @@ class cmGlobalVisualStudio10Generator : public cmGlobalVisualStudio8Generator
 public:
   static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
 
+  bool IsVisualStudioAtLeast10() const override { return true; }
+
   bool MatchesGeneratorName(const std::string& name) const override;
 
   bool SetSystemName(std::string const& s, cmMakefile* mf) override;
@@ -132,6 +134,8 @@ public:
 
   bool GetSupportsUnityBuilds() const { return this->SupportsUnityBuilds; }
 
+  virtual cm::optional<std::string> FindMSBuildCommandEarly(cmMakefile* mf);
+
   bool FindMakeProgram(cmMakefile* mf) override;
 
   bool IsIPOSupported() const override { return true; }
@@ -222,6 +226,7 @@ protected:
   bool SystemIsWindowsPhone = false;
   bool SystemIsWindowsStore = false;
   bool SystemIsAndroid = false;
+  bool MSBuildCommandInitialized = false;
 
 private:
   class Factory;
@@ -243,7 +248,6 @@ private:
   LongestSourcePath LongestSource;
 
   std::string MSBuildCommand;
-  bool MSBuildCommandInitialized;
   std::set<std::string> AndroidExecutableWarnings;
   virtual std::string FindMSBuildCommand();
   std::string FindDevEnvCommand() override;
index b46f1b9..ff1642f 100644 (file)
@@ -239,7 +239,7 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKMaxVersion(
 {
   // if the given value is set, it can either be OFF/FALSE or a valid SDK
   // string
-  if (cmProp value = mf->GetDefinition(
+  if (cmValue value = mf->GetDefinition(
         "CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM")) {
 
     // If the value is some off/false value, then there is NO maximum set.
index 0083c40..50975ff 100644 (file)
@@ -102,7 +102,7 @@ void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout,
     ext = ".csproj";
     project = "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"";
   }
-  cmProp targetExt = t->GetProperty("GENERATOR_FILE_NAME_EXT");
+  cmValue targetExt = t->GetProperty("GENERATOR_FILE_NAME_EXT");
   if (targetExt) {
     ext = *targetExt;
   }
@@ -157,11 +157,11 @@ void cmGlobalVisualStudio71Generator::WriteProjectDepends(
 // executables to the libraries it uses are also done here
 void cmGlobalVisualStudio71Generator::WriteExternalProject(
   std::ostream& fout, const std::string& name, const std::string& location,
-  const char* typeGuid,
-  const std::set<BT<std::pair<std::string, bool>>>& depends)
+  cmValue typeGuid, const std::set<BT<std::pair<std::string, bool>>>& depends)
 {
   fout << "Project(\"{"
-       << (typeGuid ? typeGuid : this->ExternalProjectType(location))
+       << (typeGuid ? typeGuid
+                    : std::string(this->ExternalProjectType(location)))
        << "}\") = \"" << name << "\", \""
        << this->ConvertToSolutionPath(location) << "\", \"{"
        << this->GetGUID(name) << "}\"\n";
@@ -198,8 +198,8 @@ void cmGlobalVisualStudio71Generator::WriteProjectConfigurations(
     std::vector<std::string> mapConfig;
     const char* dstConfig = i.c_str();
     if (target.GetProperty("EXTERNAL_MSPROJECT")) {
-      if (cmProp m = target.GetProperty("MAP_IMPORTED_CONFIG_" +
-                                        cmSystemTools::UpperCase(i))) {
+      if (cmValue m = target.GetProperty("MAP_IMPORTED_CONFIG_" +
+                                         cmSystemTools::UpperCase(i))) {
         cmExpandList(*m, mapConfig);
         if (!mapConfig.empty()) {
           dstConfig = mapConfig[0].c_str();
index 7d38199..cb3b8c1 100644 (file)
@@ -33,7 +33,7 @@ protected:
     const std::string& platformMapping = "") override;
   void WriteExternalProject(
     std::ostream& fout, const std::string& name, const std::string& path,
-    const char* typeGuid,
+    cmValue typeGuid,
     const std::set<BT<std::pair<std::string, bool>>>& depends) override;
 
   // Folders are not supported by VS 7.1.
index 0c85a04..6876e61 100644 (file)
@@ -37,6 +37,7 @@ static cmVS7FlagTable cmVS7ExtraFlagTable[] = {
     cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
   { "PrecompiledHeaderThrough", "Yu", "Precompiled Header Name", "",
     cmVS7FlagTable::UserValueRequired },
+  { "UsePrecompiledHeader", "Y-", "Don't use precompiled header", "0", 0 },
   { "WholeProgramOptimization", "LTCG", "WholeProgramOptimization", "true",
     0 },
 
@@ -107,14 +108,7 @@ void cmGlobalVisualStudio7Generator::EnableLanguage(
 {
   mf->AddDefinition("CMAKE_GENERATOR_RC", "rc");
   mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
-  if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
-    mf->AddCacheDefinition(
-      "CMAKE_CONFIGURATION_TYPES", "Debug;Release;MinSizeRel;RelWithDebInfo",
-      "Semicolon separated list of supported configuration types, "
-      "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
-      "anything else will be ignored.",
-      cmStateEnums::STRING);
-  }
+  mf->InitCMAKE_CONFIGURATION_TYPES("Debug;Release;MinSizeRel;RelWithDebInfo");
 
   // Create list of configurations requested by user's cache, if any.
   this->cmGlobalVisualStudioGenerator::EnableLanguage(lang, mf, optional);
@@ -303,6 +297,25 @@ void cmGlobalVisualStudio7Generator::Generate()
     this->CallVisualStudioMacro(MacroReload,
                                 GetSLNFile(this->LocalGenerators[0].get()));
   }
+
+  if (this->Version == VS10 && !this->CMakeInstance->GetIsInTryCompile()) {
+    std::string cmakeWarnVS10;
+    if (cmValue cached = this->CMakeInstance->GetState()->GetCacheEntryValue(
+          "CMAKE_WARN_VS10")) {
+      this->CMakeInstance->MarkCliAsUsed("CMAKE_WARN_VS10");
+      cmakeWarnVS10 = *cached;
+    } else {
+      cmSystemTools::GetEnv("CMAKE_WARN_VS10", cmakeWarnVS10);
+    }
+    if (cmakeWarnVS10.empty() || !cmIsOff(cmakeWarnVS10)) {
+      this->CMakeInstance->IssueMessage(
+        MessageType::WARNING,
+        "The \"Visual Studio 10 2010\" generator is deprecated "
+        "and will be removed in a future version of CMake."
+        "\n"
+        "Add CMAKE_WARN_VS10=OFF to the cache to disable this warning.");
+    }
+  }
 }
 
 void cmGlobalVisualStudio7Generator::OutputSLNFile(
@@ -342,17 +355,17 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations(
     if (!target->IsInBuildSystem()) {
       continue;
     }
-    cmProp expath = target->GetProperty("EXTERNAL_MSPROJECT");
+    cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT");
     if (expath) {
       std::set<std::string> allConfigurations(configs.begin(), configs.end());
-      cmProp mapping = target->GetProperty("VS_PLATFORM_MAPPING");
+      cmValue mapping = target->GetProperty("VS_PLATFORM_MAPPING");
       this->WriteProjectConfigurations(fout, target->GetName(), *target,
                                        configs, allConfigurations,
                                        mapping ? *mapping : "");
     } else {
       const std::set<std::string>& configsPartOfDefaultBuild =
         this->IsPartOfDefaultBuild(configs, projectTargets, target);
-      cmProp vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
+      cmValue vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
       if (vcprojName) {
         this->WriteProjectConfigurations(fout, *vcprojName, *target, configs,
                                          configsPartOfDefaultBuild);
@@ -374,18 +387,17 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
     bool written = false;
 
     // handle external vc project files
-    cmProp expath = target->GetProperty("EXTERNAL_MSPROJECT");
+    cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT");
     if (expath) {
       std::string project = target->GetName();
       std::string location = *expath;
 
-      this->WriteExternalProject(
-        fout, project, location,
-        cmToCStr(target->GetProperty("VS_PROJECT_TYPE")),
-        target->GetUtilities());
+      this->WriteExternalProject(fout, project, location,
+                                 target->GetProperty("VS_PROJECT_TYPE"),
+                                 target->GetUtilities());
       written = true;
     } else {
-      cmProp vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
+      cmValue vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
       if (vcprojName) {
         cmLocalGenerator* lg = target->GetLocalGenerator();
         std::string dir = lg->GetCurrentBinaryDirectory();
@@ -438,7 +450,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetDepends(
     if (!target->IsInBuildSystem()) {
       continue;
     }
-    cmProp vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
+    cmValue vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
     if (vcprojName) {
       std::string dir =
         target->GetLocalGenerator()->GetCurrentSourceDirectory();
@@ -526,7 +538,7 @@ void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections(
           extensibilityAddInsOverridden = true;
         }
         fout << "\tGlobalSection(" << name << ") = " << sectionType << "\n";
-        cmProp p = root->GetMakefile()->GetProperty(it);
+        cmValue p = root->GetMakefile()->GetProperty(it);
         std::vector<std::string> keyValuePairs = cmExpandedList(p ? *p : "");
         for (std::string const& itPair : keyValuePairs) {
           const std::string::size_type posEqual = itPair.find('=');
@@ -625,7 +637,7 @@ std::string cmGlobalVisualStudio7Generator::WriteUtilityDepend(
 std::string cmGlobalVisualStudio7Generator::GetGUID(std::string const& name)
 {
   std::string const& guidStoreName = name + "_GUID_CMAKE";
-  if (cmProp storedGUID =
+  if (cmValue storedGUID =
         this->CMakeInstance->GetCacheDefinition(guidStoreName)) {
     return *storedGUID;
   }
@@ -675,7 +687,7 @@ std::set<std::string> cmGlobalVisualStudio7Generator::IsPartOfDefaultBuild(
           "CMAKE_VS_INCLUDE_" + t + "_TO_DEFAULT_BUILD";
         // inspect CMAKE_VS_INCLUDE_<t>_TO_DEFAULT_BUILD properties
         for (std::string const& i : configs) {
-          cmProp propertyValue =
+          cmValue propertyValue =
             target->Target->GetMakefile()->GetDefinition(propertyName);
           if (propertyValue &&
               cmIsOn(cmGeneratorExpression::Evaluate(
index 148762e..8e762cf 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "cmGlobalGeneratorFactory.h"
 #include "cmGlobalVisualStudioGenerator.h"
+#include "cmValue.h"
 
 class cmTarget;
 struct cmIDEFlagTable;
@@ -142,7 +143,7 @@ protected:
 
   virtual void WriteExternalProject(
     std::ostream& fout, const std::string& name, const std::string& path,
-    const char* typeGuid,
+    cmValue typeGuid,
     const std::set<BT<std::pair<std::string, bool>>>& dependencies) = 0;
 
   std::string ConvertToSolutionPath(const std::string& path);
index b19212e..1e45813 100644 (file)
@@ -67,12 +67,55 @@ void cmGlobalVisualStudio8Generator::AddPlatformDefinitions(cmMakefile* mf)
 bool cmGlobalVisualStudio8Generator::SetGeneratorPlatform(std::string const& p,
                                                           cmMakefile* mf)
 {
-  if (!this->PlatformInGeneratorName) {
-    this->GeneratorPlatform = p;
-    return this->cmGlobalVisualStudio7Generator::SetGeneratorPlatform("", mf);
-  } else {
+  if (this->PlatformInGeneratorName) {
+    // This is an old-style generator name that contains the platform name.
+    // No explicit platform specification is supported, so pass it through
+    // to our base class implementation, which errors on non-empty platforms.
     return this->cmGlobalVisualStudio7Generator::SetGeneratorPlatform(p, mf);
   }
+
+  this->GeneratorPlatform = p;
+
+  // FIXME: Add CMAKE_GENERATOR_PLATFORM field to set the framework.
+  // For now, just report the generator's default, if any.
+  if (cm::optional<std::string> const& targetFrameworkVersion =
+        this->GetTargetFrameworkVersion()) {
+    mf->AddDefinition("CMAKE_VS_TARGET_FRAMEWORK_VERSION",
+                      *targetFrameworkVersion);
+  }
+  if (cm::optional<std::string> const& targetFrameworkIdentifier =
+        this->GetTargetFrameworkIdentifier()) {
+    mf->AddDefinition("CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER",
+                      *targetFrameworkIdentifier);
+  }
+  if (cm::optional<std::string> const& targetFrameworkTargetsVersion =
+        this->GetTargetFrameworkTargetsVersion()) {
+    mf->AddDefinition("CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION",
+                      *targetFrameworkTargetsVersion);
+  }
+
+  // The generator name does not contain the platform name, and so supports
+  // explicit platform specification.  We handled that above, so pass an
+  // empty platform name to our base class implementation so it does not error.
+  return this->cmGlobalVisualStudio7Generator::SetGeneratorPlatform("", mf);
+}
+
+cm::optional<std::string> const&
+cmGlobalVisualStudio8Generator::GetTargetFrameworkVersion() const
+{
+  return this->DefaultTargetFrameworkVersion;
+}
+
+cm::optional<std::string> const&
+cmGlobalVisualStudio8Generator::GetTargetFrameworkIdentifier() const
+{
+  return this->DefaultTargetFrameworkIdentifier;
+}
+
+cm::optional<std::string> const&
+cmGlobalVisualStudio8Generator::GetTargetFrameworkTargetsVersion() const
+{
+  return this->DefaultTargetFrameworkTargetsVersion;
 }
 
 std::string cmGlobalVisualStudio8Generator::GetGenerateStampList()
@@ -245,8 +288,8 @@ void cmGlobalVisualStudio8Generator::WriteProjectConfigurations(
     std::vector<std::string> mapConfig;
     const char* dstConfig = i.c_str();
     if (target.GetProperty("EXTERNAL_MSPROJECT")) {
-      if (cmProp m = target.GetProperty("MAP_IMPORTED_CONFIG_" +
-                                        cmSystemTools::UpperCase(i))) {
+      if (cmValue m = target.GetProperty("MAP_IMPORTED_CONFIG_" +
+                                         cmSystemTools::UpperCase(i))) {
         cmExpandList(*m, mapConfig);
         if (!mapConfig.empty()) {
           dstConfig = mapConfig[0].c_str();
@@ -287,14 +330,14 @@ bool cmGlobalVisualStudio8Generator::NeedsDeploy(
     return false;
   }
 
-  if (cmProp prop = target.GetProperty("VS_SOLUTION_DEPLOY")) {
+  if (cmValue prop = target.GetProperty("VS_SOLUTION_DEPLOY")) {
     // If set, it dictates behavior
     return cmIsOn(
       cmGeneratorExpression::Evaluate(*prop, target.LocalGenerator, config));
   }
 
   // To be deprecated, disable deployment even if target supports it.
-  if (cmProp prop = target.GetProperty("VS_NO_SOLUTION_DEPLOY")) {
+  if (cmValue prop = target.GetProperty("VS_NO_SOLUTION_DEPLOY")) {
     if (cmIsOn(cmGeneratorExpression::Evaluate(*prop, target.LocalGenerator,
                                                config))) {
       // If true, always disable deployment
@@ -370,6 +413,7 @@ static cmVS7FlagTable cmVS8ExtraFlagTable[] = {
     cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
   { "PrecompiledHeaderThrough", "Yu", "Precompiled Header Name", "",
     cmVS7FlagTable::UserValueRequired },
+  { "UsePrecompiledHeader", "Y-", "Don't use precompiled header", "0", 0 },
   // There is no YX option in the VS8 IDE.
 
   // Exception handling mode.  If no entries match, it will be FALSE.
index 96e3553..b6ecdf0 100644 (file)
@@ -2,6 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #pragma once
 
+#include <cm/optional>
+
 #include "cmGlobalVisualStudio71Generator.h"
 
 /** \class cmGlobalVisualStudio8Generator
@@ -24,6 +26,10 @@ public:
 
   bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;
 
+  cm::optional<std::string> const& GetTargetFrameworkVersion() const;
+  cm::optional<std::string> const& GetTargetFrameworkIdentifier() const;
+  cm::optional<std::string> const& GetTargetFrameworkTargetsVersion() const;
+
   /**
    * Override Configure and Generate to add the build-system check
    * target.
@@ -76,4 +82,8 @@ protected:
 
   std::string Name;
   std::string WindowsCEVersion;
+
+  cm::optional<std::string> DefaultTargetFrameworkVersion;
+  cm::optional<std::string> DefaultTargetFrameworkIdentifier;
+  cm::optional<std::string> DefaultTargetFrameworkTargetsVersion;
 };
index cdecea0..f9bd67e 100644 (file)
@@ -519,7 +519,7 @@ std::string cmGlobalVisualStudioGenerator::GetUtilityDepend(
 std::string cmGlobalVisualStudioGenerator::GetStartupProjectName(
   cmLocalGenerator const* root) const
 {
-  cmProp n = root->GetMakefile()->GetProperty("VS_STARTUP_PROJECT");
+  cmValue n = root->GetMakefile()->GetProperty("VS_STARTUP_PROJECT");
   if (cmNonempty(n)) {
     std::string startup = *n;
     if (this->FindTarget(startup)) {
@@ -820,7 +820,7 @@ bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly(
   // This allows the project to control the language choice in
   // a target with none of its own sources, e.g. when also using
   // object libraries.
-  cmProp linkLang = gt->GetProperty("LINKER_LANGUAGE");
+  cmValue linkLang = gt->GetProperty("LINKER_LANGUAGE");
   if (cmNonempty(linkLang)) {
     languages.insert(*linkLang);
   }
index 151f39f..23c8a02 100644 (file)
@@ -167,11 +167,6 @@ protected:
 
   void WriteSLNHeader(std::ostream& fout);
 
-  FindMakeProgramStage GetFindMakeProgramStage() const override
-  {
-    return FindMakeProgramStage::Early;
-  }
-
   bool ComputeTargetDepends() override;
   class VSDependSet : public std::set<std::string>
   {
@@ -201,7 +196,7 @@ protected:
 private:
   virtual std::string GetVSMakeProgram() = 0;
   void PrintCompilerAdvice(std::ostream&, std::string const&,
-                           const char*) const override
+                           cmValue) const override
   {
   }
 
index d0ad53e..b5a6b9f 100644 (file)
@@ -401,6 +401,12 @@ cmGlobalVisualStudioVersionedGenerator::cmGlobalVisualStudioVersionedGenerator(
     this->DefaultPlatformName = VSHostPlatformName();
     this->DefaultPlatformToolsetHostArchitecture = VSHostArchitecture();
   }
+  if (this->Version >= cmGlobalVisualStudioGenerator::VS17) {
+    // FIXME: Search for an existing framework?  Under '%ProgramFiles(x86)%',
+    // see 'Reference Assemblies\Microsoft\Framework\.NETFramework'.
+    // Use a version installed by VS 2022 without a separate component.
+    this->DefaultTargetFrameworkVersion = "v4.7.2";
+  }
 }
 
 bool cmGlobalVisualStudioVersionedGenerator::MatchesGeneratorName(
@@ -436,6 +442,11 @@ bool cmGlobalVisualStudioVersionedGenerator::MatchesGeneratorName(
 bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance(
   std::string const& i, cmMakefile* mf)
 {
+  if (this->LastGeneratorInstanceString &&
+      i == *(this->LastGeneratorInstanceString)) {
+    return true;
+  }
+
   if (!i.empty()) {
     if (!this->vsSetupAPIHelper.SetVSInstance(i)) {
       std::ostringstream e;
@@ -467,11 +478,16 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance(
   // Save the selected instance persistently.
   std::string genInstance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE");
   if (vsInstance != genInstance) {
-    this->CMakeInstance->AddCacheEntry(
-      "CMAKE_GENERATOR_INSTANCE", vsInstance.c_str(),
-      "Generator instance identifier.", cmStateEnums::INTERNAL);
+    this->CMakeInstance->AddCacheEntry("CMAKE_GENERATOR_INSTANCE", vsInstance,
+                                       "Generator instance identifier.",
+                                       cmStateEnums::INTERNAL);
   }
 
+  // The selected instance may have a different MSBuild than previously found.
+  this->MSBuildCommandInitialized = false;
+
+  this->LastGeneratorInstanceString = i;
+
   return true;
 }
 
@@ -712,6 +728,17 @@ cmGlobalVisualStudioVersionedGenerator::GetWindows10SDKMaxVersionDefault(
   return std::string();
 }
 
+cm::optional<std::string>
+cmGlobalVisualStudioVersionedGenerator::FindMSBuildCommandEarly(cmMakefile* mf)
+{
+  std::string instance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE");
+  if (!this->SetGeneratorInstance(instance, mf)) {
+    cmSystemTools::SetFatalErrorOccured();
+    return {};
+  }
+  return this->cmGlobalVisualStudio14Generator::FindMSBuildCommandEarly(mf);
+}
+
 std::string cmGlobalVisualStudioVersionedGenerator::FindMSBuildCommand()
 {
   std::string msbuild;
index f07492d..2aed65b 100644 (file)
@@ -8,6 +8,8 @@
 #include <memory>
 #include <string>
 
+#include <cm/optional>
+
 #include "cmGlobalVisualStudio14Generator.h"
 #include "cmVSSetupHelper.h"
 
@@ -29,6 +31,8 @@ public:
 
   bool GetVSInstance(std::string& dir) const;
 
+  cm::optional<std::string> FindMSBuildCommandEarly(cmMakefile* mf) override;
+
   cm::optional<std::string> GetVSInstanceVersion() const override;
 
   AuxToolset FindAuxToolset(std::string& version,
@@ -72,4 +76,5 @@ private:
   class Factory17;
   friend class Factory17;
   mutable cmVSSetupAPIHelper vsSetupAPIHelper;
+  cm::optional<std::string> LastGeneratorInstanceString;
 };
index 77403b0..f34ef62 100644 (file)
@@ -431,14 +431,7 @@ void cmGlobalXCodeGenerator::EnableLanguage(
 {
   mf->AddDefinition("XCODE", "1");
   mf->AddDefinition("XCODE_VERSION", this->VersionString);
-  if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
-    mf->AddCacheDefinition(
-      "CMAKE_CONFIGURATION_TYPES", "Debug;Release;MinSizeRel;RelWithDebInfo",
-      "Semicolon separated list of supported configuration types, "
-      "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
-      "anything else will be ignored.",
-      cmStateEnums::STRING);
-  }
+  mf->InitCMAKE_CONFIGURATION_TYPES("Debug;Release;MinSizeRel;RelWithDebInfo");
   mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
   this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
   this->ComputeArchitectures(mf);
@@ -948,11 +941,11 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
   gtgt->AddExplicitLanguageFlags(flags, *sf);
 
   const std::string COMPILE_FLAGS("COMPILE_FLAGS");
-  if (cmProp cflags = sf->GetProperty(COMPILE_FLAGS)) {
+  if (cmValue cflags = sf->GetProperty(COMPILE_FLAGS)) {
     lg->AppendFlags(flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
   }
   const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
-  if (cmProp coptions = sf->GetProperty(COMPILE_OPTIONS)) {
+  if (cmValue coptions = sf->GetProperty(COMPILE_OPTIONS)) {
     lg->AppendCompileOptions(
       flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
   }
@@ -960,7 +953,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
   // Add per-source definitions.
   BuildObjectListOrString flagsBuild(this, false);
   const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
-  if (cmProp compile_defs = sf->GetProperty(COMPILE_DEFINITIONS)) {
+  if (cmValue compile_defs = sf->GetProperty(COMPILE_DEFINITIONS)) {
     this->AppendDefines(
       flagsBuild,
       genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS).c_str(),
@@ -981,7 +974,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
   // Add per-source include directories.
   std::vector<std::string> includes;
   const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
-  if (cmProp cincludes = sf->GetProperty(INCLUDE_DIRECTORIES)) {
+  if (cmValue cincludes = sf->GetProperty(INCLUDE_DIRECTORIES)) {
     lg->AppendIncludeDirectories(
       includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES),
       *sf);
@@ -1013,7 +1006,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
   }
 
   // Add user-specified file attributes.
-  cmProp extraFileAttributes = sf->GetProperty("XCODE_FILE_ATTRIBUTES");
+  cmValue extraFileAttributes = sf->GetProperty("XCODE_FILE_ATTRIBUTES");
   if (extraFileAttributes) {
     // Expand the list of attributes.
     std::vector<std::string> attributes = cmExpandedList(*extraFileAttributes);
@@ -1104,7 +1097,7 @@ std::string GetSourcecodeValueFromFileExtension(
   } else if (ext == "h") {
     sourcecode += ".c.h";
   } else if (ext == "hxx" || ext == "hpp" || ext == "txx" || ext == "pch" ||
-             ext == "hh") {
+             ext == "hh" || ext == "inl") {
     sourcecode += ".cpp.h";
   } else if (ext == "png" || ext == "gif" || ext == "jpg") {
     keepLastKnownFileType = true;
@@ -1201,9 +1194,9 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
   bool useLastKnownFileType = false;
   std::string fileType;
   if (sf) {
-    if (cmProp e = sf->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) {
+    if (cmValue e = sf->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) {
       fileType = *e;
-    } else if (cmProp l = sf->GetProperty("XCODE_LAST_KNOWN_FILE_TYPE")) {
+    } else if (cmValue l = sf->GetProperty("XCODE_LAST_KNOWN_FILE_TYPE")) {
       useLastKnownFileType = true;
       fileType = *l;
     }
@@ -1674,7 +1667,7 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmGeneratorTarget* gtgt)
     fout << "\n";
   }
   if (cmSourceFile* sf = mf->GetOrCreateSource(fname)) {
-    sf->SetProperty("LANGUAGE", llang.c_str());
+    sf->SetProperty("LANGUAGE", llang);
     gtgt->AddSource(fname);
   }
 }
@@ -1763,9 +1756,6 @@ void cmGlobalXCodeGenerator::CreateCustomCommands(
       if (sourceFile->GetCustomCommand() &&
           visited.insert(sourceFile).second) {
         commands.push_back(*sourceFile->GetCustomCommand());
-        if (this->XcodeBuildSystem >= BuildSystem::Twelve) {
-          this->CustomCommandRoots[sourceFile].insert(gtgt);
-        }
       }
     }
     // create custom commands phase
@@ -2420,7 +2410,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
     this->CurrentLocalGenerator->GetStaticLibraryFlags(
       extraLinkOptions, configName, llang, gtgt);
   } else {
-    cmProp targetLinkFlags = gtgt->GetProperty("LINK_FLAGS");
+    cmValue targetLinkFlags = gtgt->GetProperty("LINK_FLAGS");
     if (targetLinkFlags) {
       this->CurrentLocalGenerator->AppendFlags(extraLinkOptions,
                                                *targetLinkFlags);
@@ -2428,7 +2418,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
     if (!configName.empty()) {
       std::string linkFlagsVar =
         cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(configName));
-      if (cmProp linkFlags = gtgt->GetProperty(linkFlagsVar)) {
+      if (cmValue linkFlags = gtgt->GetProperty(linkFlagsVar)) {
         this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, *linkFlags);
       }
     }
@@ -2465,8 +2455,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
   std::string pnsuffix;
   gtgt->GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
 
-  cmProp version = gtgt->GetProperty("VERSION");
-  cmProp soversion = gtgt->GetProperty("SOVERSION");
+  cmValue version = gtgt->GetProperty("VERSION");
+  cmValue soversion = gtgt->GetProperty("SOVERSION");
   if (!gtgt->HasSOName(configName) || gtgt->IsFrameworkOnApple()) {
     version = nullptr;
     soversion = nullptr;
@@ -2530,7 +2520,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
         std::string fw_version = gtgt->GetFrameworkVersion();
         buildSettings->AddAttribute("FRAMEWORK_VERSION",
                                     this->CreateString(fw_version));
-        cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION");
+        cmValue ext = gtgt->GetProperty("BUNDLE_EXTENSION");
         if (ext) {
           buildSettings->AddAttribute("WRAPPER_EXTENSION",
                                       this->CreateString(*ext));
@@ -2571,7 +2561,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
           extraLinkOptions += " ";
           extraLinkOptions += createFlags;
         }
-        cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION");
+        cmValue ext = gtgt->GetProperty("BUNDLE_EXTENSION");
         if (ext) {
           buildSettings->AddAttribute("WRAPPER_EXTENSION",
                                       this->CreateString(*ext));
@@ -2605,7 +2595,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
         std::string fw_version = gtgt->GetFrameworkVersion();
         buildSettings->AddAttribute("FRAMEWORK_VERSION",
                                     this->CreateString(fw_version));
-        cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION");
+        cmValue ext = gtgt->GetProperty("BUNDLE_EXTENSION");
         if (ext) {
           buildSettings->AddAttribute("WRAPPER_EXTENSION",
                                       this->CreateString(*ext));
@@ -2644,7 +2634,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
 
       // Handle bundles and normal executables separately.
       if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
-        cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION");
+        cmValue ext = gtgt->GetProperty("BUNDLE_EXTENSION");
         if (ext) {
           buildSettings->AddAttribute("WRAPPER_EXTENSION",
                                       this->CreateString(*ext));
@@ -3090,7 +3080,7 @@ const char* cmGlobalXCodeGenerator::GetTargetLinkFlagsVar(
 const char* cmGlobalXCodeGenerator::GetTargetFileType(
   cmGeneratorTarget* target)
 {
-  if (cmProp e = target->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) {
+  if (cmValue e = target->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) {
     return e->c_str();
   }
 
@@ -3123,7 +3113,7 @@ const char* cmGlobalXCodeGenerator::GetTargetFileType(
 const char* cmGlobalXCodeGenerator::GetTargetProductType(
   cmGeneratorTarget* target)
 {
-  if (cmProp e = target->GetProperty("XCODE_PRODUCT_TYPE")) {
+  if (cmValue e = target->GetProperty("XCODE_PRODUCT_TYPE")) {
     return e->c_str();
   }
 
@@ -3242,15 +3232,14 @@ std::string cmGlobalXCodeGenerator::GetOrCreateId(const std::string& name,
                                                   const std::string& id)
 {
   std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE");
-  cmProp storedGUID = this->CMakeInstance->GetCacheDefinition(guidStoreName);
+  cmValue storedGUID = this->CMakeInstance->GetCacheDefinition(guidStoreName);
 
   if (storedGUID) {
     return *storedGUID;
   }
 
-  this->CMakeInstance->AddCacheEntry(guidStoreName, id.c_str(),
-                                     "Stored Xcode object GUID",
-                                     cmStateEnums::INTERNAL);
+  this->CMakeInstance->AddCacheEntry(
+    guidStoreName, id, "Stored Xcode object GUID", cmStateEnums::INTERNAL);
 
   return id;
 }
@@ -3419,7 +3408,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
   std::map<std::string, std::vector<std::string>> targetProductNameMap;
   bool useLinkPhase = false;
   bool forceLinkPhase = false;
-  cmProp prop =
+  cmValue prop =
     target->GetTarget()->GetProperty("XCODE_LINK_BUILD_PHASE_MODE");
   if (prop) {
     if (*prop == "BUILT_ONLY") {
@@ -3792,7 +3781,7 @@ void cmGlobalXCodeGenerator::AddEmbeddedObjects(
   if (!(isFrameworkTarget || isBundleTarget || isCFBundleTarget)) {
     return;
   }
-  cmProp files = gt->GetProperty(embedPropertyName);
+  cmValue files = gt->GetProperty(embedPropertyName);
   if (!files) {
     return;
   }
@@ -3807,7 +3796,7 @@ void cmGlobalXCodeGenerator::AddEmbeddedObjects(
                                     this->CreateString(dstSubfolderSpec));
   copyFilesBuildPhase->AddAttribute(
     "name", this->CreateString(copyFilesBuildPhaseName));
-  if (cmProp fwEmbedPath =
+  if (cmValue fwEmbedPath =
         gt->GetProperty(cmStrCat(embedPropertyName, "_PATH"))) {
     copyFilesBuildPhase->AddAttribute("dstPath",
                                       this->CreateString(*fwEmbedPath));
@@ -3817,7 +3806,7 @@ void cmGlobalXCodeGenerator::AddEmbeddedObjects(
   copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
                                     this->CreateString("0"));
   cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
-  // Collect all embedded frameworks and add them to build phase
+  // Collect all embedded frameworks and dylibs and add them to build phase
   std::vector<std::string> relFiles = cmExpandedList(*files);
   for (std::string const& relFile : relFiles) {
     cmXCodeObject* buildFile{ nullptr };
@@ -3847,7 +3836,8 @@ void cmGlobalXCodeGenerator::AddEmbeddedObjects(
       } else {
         buildFile = it->second;
       }
-    } else if (cmSystemTools::IsPathToFramework(relFile)) {
+    } else if (cmSystemTools::IsPathToFramework(relFile) ||
+               cmSystemTools::IsPathToMacOSSharedLibrary(relFile)) {
       // This is a regular string path - create file reference
       auto it = this->EmbeddedLibRefs.find(relFile);
       if (it == this->EmbeddedLibRefs.end()) {
@@ -3913,6 +3903,8 @@ void cmGlobalXCodeGenerator::AddEmbeddedFrameworks(cmXCodeObject* target)
 {
   static const auto dstSubfolderSpec = "10";
 
+  // Despite the name, by default Xcode uses "Embed Frameworks" build phase for
+  // both frameworks and dynamic libraries
   this->AddEmbeddedObjects(target, "Embed Frameworks",
                            "XCODE_EMBED_FRAMEWORKS", dstSubfolderSpec,
                            NoActionOnCopyByDefault);
@@ -4191,8 +4183,8 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
                            this->CreateString(defaultConfigName));
   cmXCodeObject* buildSettings =
     this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
-  cmProp sysroot = this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT");
-  cmProp deploymentTarget =
+  cmValue sysroot = this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT");
+  cmValue deploymentTarget =
     this->CurrentMakefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
   if (sysroot) {
     buildSettings->AddAttribute("SDKROOT", this->CreateString(*sysroot));
@@ -4225,7 +4217,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
   }
   if (this->GetLanguageEnabled("Swift")) {
     std::string swiftVersion;
-    if (cmProp vers = this->CurrentMakefile->GetDefinition(
+    if (cmValue vers = this->CurrentMakefile->GetDefinition(
           "CMAKE_Swift_LANGUAGE_VERSION")) {
       swiftVersion = *vers;
     } else if (this->XcodeVersion >= 102) {
@@ -4348,7 +4340,7 @@ std::string cmGlobalXCodeGenerator::GetObjectsDirectory(
 void cmGlobalXCodeGenerator::ComputeArchitectures(cmMakefile* mf)
 {
   this->Architectures.clear();
-  cmProp sysroot = mf->GetDefinition("CMAKE_OSX_SYSROOT");
+  cmValue sysroot = mf->GetDefinition("CMAKE_OSX_SYSROOT");
   if (sysroot) {
     mf->GetDefExpandList("CMAKE_OSX_ARCHITECTURES", this->Architectures);
   }
@@ -4361,7 +4353,7 @@ void cmGlobalXCodeGenerator::ComputeArchitectures(cmMakefile* mf)
     // With no ARCHS we use ONLY_ACTIVE_ARCH and possibly a
     // platform-specific default ARCHS placeholder value.
     // Look up the arch that Xcode chooses in this case.
-    if (cmProp arch = mf->GetDefinition("CMAKE_XCODE_ARCHS")) {
+    if (cmValue arch = mf->GetDefinition("CMAKE_XCODE_ARCHS")) {
       this->ObjectDirArchDefault = *arch;
       // We expect only one arch but choose the first just in case.
       std::string::size_type pos = this->ObjectDirArchDefault.find(';');
@@ -4555,7 +4547,7 @@ bool cmGlobalXCodeGenerator::OutputXCodeSharedSchemes(
       continue;
     }
 
-    cmProp testee = obj->GetTarget()->GetProperty("XCTEST_TESTEE");
+    cmValue testee = obj->GetTarget()->GetProperty("XCTEST_TESTEE");
     if (!testee) {
       continue;
     }
@@ -4738,7 +4730,7 @@ std::string cmGlobalXCodeGenerator::LookupFlags(
 {
   if (!varNameLang.empty()) {
     std::string varName = cmStrCat(varNamePrefix, varNameLang, varNameSuffix);
-    if (cmProp varValue = this->CurrentMakefile->GetDefinition(varName)) {
+    if (cmValue varValue = this->CurrentMakefile->GetDefinition(varName)) {
       if (!varValue->empty()) {
         return *varValue;
       }
@@ -4860,7 +4852,7 @@ bool cmGlobalXCodeGenerator::HasKnownObjectFileLocation(
 
 bool cmGlobalXCodeGenerator::UseEffectivePlatformName(cmMakefile* mf) const
 {
-  cmProp epnValue = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+  cmValue epnValue = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
     "XCODE_EMIT_EFFECTIVE_PLATFORM_NAME");
 
   if (!epnValue) {
index 1e1b344..4d7ee90 100644 (file)
@@ -138,11 +138,6 @@ protected:
   void AddExtraIDETargets() override;
   void Generate() override;
 
-  FindMakeProgramStage GetFindMakeProgramStage() const override
-  {
-    return FindMakeProgramStage::Early;
-  }
-
 private:
   enum EmbedActionFlags
   {
@@ -327,7 +322,7 @@ private:
   bool XcodeBuildCommandInitialized;
 
   void PrintCompilerAdvice(std::ostream&, std::string const&,
-                           const char*) const override
+                           cmValue) const override
   {
   }
 
index 122bda5..ab18e2a 100644 (file)
 #include "cmLinkItem.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 namespace {
@@ -232,7 +232,7 @@ void cmGraphVizWriter::ReadSettings(
 
 #define set_if_set(var, cmakeDefinition)                                      \
   do {                                                                        \
-    cmProp value = mf.GetDefinition(cmakeDefinition);                         \
+    cmValue value = mf.GetDefinition(cmakeDefinition);                        \
     if (value) {                                                              \
       (var) = *value;                                                         \
     }                                                                         \
@@ -244,7 +244,7 @@ void cmGraphVizWriter::ReadSettings(
 
 #define set_bool_if_set(var, cmakeDefinition)                                 \
   do {                                                                        \
-    cmProp value = mf.GetDefinition(cmakeDefinition);                         \
+    cmValue value = mf.GetDefinition(cmakeDefinition);                        \
     if (value) {                                                              \
       (var) = cmIsOn(*value);                                                 \
     }                                                                         \
index ce1f030..7b0320c 100644 (file)
@@ -120,6 +120,7 @@ bool cmIncludeCommand(std::vector<std::string> const& args,
       case cmPolicies::WARN:
         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0024) << "\n";
         modal = "should";
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         break;
       case cmPolicies::REQUIRED_IF_USED:
index b408f72..23427a1 100644 (file)
@@ -13,6 +13,7 @@
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 static void GetIncludes(cmMakefile& mf, const std::string& arg,
                         std::vector<std::string>& incs);
index 5b532ce..c8b4a39 100644 (file)
@@ -77,9 +77,8 @@ bool cmIncludeExternalMSProjectCommand(std::vector<std::string> const& args,
 
     if (!customGuid.empty()) {
       std::string guidVariable = utility_name + "_GUID_CMAKE";
-      mf.GetCMakeInstance()->AddCacheEntry(guidVariable, customGuid.c_str(),
-                                           "Stored GUID",
-                                           cmStateEnums::INTERNAL);
+      mf.GetCMakeInstance()->AddCacheEntry(
+        guidVariable, customGuid, "Stored GUID", cmStateEnums::INTERNAL);
     }
 
     // Create a target instance for this utility.
index aefd098..e0a6958 100644 (file)
@@ -7,6 +7,7 @@
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 namespace {
index 655ebd6..cdcc7df 100644 (file)
@@ -14,7 +14,7 @@ bool cmIncludeRegularExpressionCommand(std::vector<std::string> const& args,
   }
 
   cmMakefile& mf = status.GetMakefile();
-  mf.SetIncludeRegularExpression(args[0].c_str());
+  mf.SetIncludeRegularExpression(args[0]);
 
   if (args.size() > 1) {
     mf.SetComplainRegularExpression(args[1]);
index 79109b5..eaf88f6 100644 (file)
@@ -35,7 +35,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
+#include "cmRange.h"
 #include "cmRuntimeDependencyArchive.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
@@ -43,6 +43,7 @@
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTargetExport.h"
+#include "cmValue.h"
 
 namespace {
 
@@ -681,8 +682,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
         te->LibraryGenerator = libraryGenerator.get();
         te->RuntimeGenerator = runtimeGenerator.get();
         te->ObjectsGenerator = objectGenerator.get();
-        te->InterfaceIncludeDirectories =
-          cmJoin(includesArgs.GetIncludeDirs(), ";");
+        target.AddInstallIncludeDirectories(
+          cmMakeRange(includesArgs.GetIncludeDirs()));
         te->NamelinkOnly = namelinkOnly;
         helper.Makefile->GetGlobalGenerator()
           ->GetExportSets()[exports]
@@ -925,7 +926,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
     }
 
     if (createInstallGeneratorsForTargetFileSets && !namelinkOnly) {
-      cmProp files = target.GetProperty("PRIVATE_HEADER");
+      cmValue files = target.GetProperty("PRIVATE_HEADER");
       if (cmNonempty(files)) {
         std::vector<std::string> relFiles = cmExpandedList(*files);
         std::vector<std::string> absFiles;
@@ -1390,6 +1391,7 @@ bool HandleFilesMode(std::vector<std::string> const& args,
         case cmPolicies::WARN:
           e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0062) << "\n";
           modal = "should";
+          CM_FALLTHROUGH;
         case cmPolicies::OLD:
           break;
         case cmPolicies::REQUIRED_IF_USED:
@@ -1397,6 +1399,7 @@ bool HandleFilesMode(std::vector<std::string> const& args,
         case cmPolicies::NEW:
           modal = "may";
           messageType = MessageType::FATAL_ERROR;
+          break;
       }
       if (modal) {
         e << "The file\n  " << file
diff --git a/Source/cmInstallMode.h b/Source/cmInstallMode.h
new file mode 100644 (file)
index 0000000..5343d34
--- /dev/null
@@ -0,0 +1,17 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+/**
+ * Enumerate types known to file(INSTALL).
+ */
+enum class cmInstallMode
+{
+  COPY,
+  ABS_SYMLINK,
+  ABS_SYMLINK_OR_COPY,
+  REL_SYMLINK,
+  REL_SYMLINK_OR_COPY,
+  SYMLINK,
+  SYMLINK_OR_COPY
+};
index 794694e..0a8e065 100644 (file)
@@ -57,6 +57,7 @@ void cmInstallSubdirectoryGenerator::GenerateScript(std::ostream& os)
       this->LocalGenerator->GetPolicyStatus(cmPolicies::CMP0082);
     switch (status) {
       case cmPolicies::WARN:
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         // OLD behavior is handled in cmLocalGenerator::GenerateInstallRules()
         break;
index 35165cf..ae11afc 100644 (file)
@@ -2,11 +2,13 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmInstallTargetGenerator.h"
 
+#include <algorithm>
 #include <cassert>
 #include <map>
 #include <set>
 #include <sstream>
 #include <utility>
+#include <vector>
 
 #include "cmComputeLinkInformation.h"
 #include "cmGeneratorExpression.h"
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 namespace {
@@ -208,7 +210,7 @@ cmInstallTargetGenerator::Files cmInstallTargetGenerator::GetFiles(
 
         // Get App Bundle Extension
         std::string ext;
-        if (cmProp p = this->Target->GetProperty("BUNDLE_EXTENSION")) {
+        if (cmValue p = this->Target->GetProperty("BUNDLE_EXTENSION")) {
           ext = *p;
         } else {
           ext = "app";
@@ -680,33 +682,52 @@ void cmInstallTargetGenerator::AddChrpathPatchRule(
            " this limitation.";
       mf->IssueMessage(MessageType::WARNING, msg.str());
     } else {
-      // Note: These paths are kept unique to avoid
-      // install_name_tool corruption.
-      std::set<std::string> runpaths;
-      for (std::string const& i : oldRuntimeDirs) {
-        std::string runpath =
-          mf->GetGlobalGenerator()->ExpandCFGIntDir(i, config);
-
-        if (runpaths.find(runpath) == runpaths.end()) {
-          runpaths.insert(runpath);
-          os << indent << "execute_process(COMMAND " << installNameTool
-             << "\n";
-          os << indent << "  -delete_rpath \"" << runpath << "\"\n";
-          os << indent << "  \"" << toDestDirPath << "\")\n";
+      // To be consistent with older versions, runpath changes must be ordered,
+      // deleted first, then added, *and* the same path must only appear once.
+      std::map<std::string, std::string> runpath_change;
+      std::vector<std::string> ordered;
+      for (std::string const& dir : oldRuntimeDirs) {
+        // Normalize path and add to map of changes to make
+        auto iter_inserted = runpath_change.insert(
+          { mf->GetGlobalGenerator()->ExpandCFGIntDir(dir, config),
+            "delete" });
+        if (iter_inserted.second) {
+          // Add path to ordered list of changes
+          ordered.push_back(iter_inserted.first->first);
         }
       }
 
-      runpaths.clear();
-      for (std::string const& i : newRuntimeDirs) {
-        std::string runpath =
-          mf->GetGlobalGenerator()->ExpandCFGIntDir(i, config);
+      for (std::string const& dir : newRuntimeDirs) {
+        // Normalize path and add to map of changes to make
+        auto iter_inserted = runpath_change.insert(
+          { mf->GetGlobalGenerator()->ExpandCFGIntDir(dir, config), "add" });
+        if (iter_inserted.second) {
+          // Add path to ordered list of changes
+          ordered.push_back(iter_inserted.first->first);
+        } else if (iter_inserted.first->second != "add") {
+          // Rpath was requested to be deleted and then later re-added. Drop it
+          // from the list by marking as an empty value.
+          iter_inserted.first->second.clear();
+        }
+      }
 
-        if (runpaths.find(runpath) == runpaths.end()) {
-          os << indent << "execute_process(COMMAND " << installNameTool
-             << "\n";
-          os << indent << "  -add_rpath \"" << runpath << "\"\n";
-          os << indent << "  \"" << toDestDirPath << "\")\n";
+      // Remove rpaths that are unchanged (value was set to empty)
+      ordered.erase(
+        std::remove_if(ordered.begin(), ordered.end(),
+                       [&runpath_change](const std::string& runpath) {
+                         return runpath_change.find(runpath)->second.empty();
+                       }),
+        ordered.end());
+
+      if (!ordered.empty()) {
+        os << indent << "execute_process(COMMAND " << installNameTool << "\n";
+        for (std::string const& runpath : ordered) {
+          // Either 'add_rpath' or 'delete_rpath' since we've removed empty
+          // entries
+          os << indent << "  -" << runpath_change.find(runpath)->second
+             << "_rpath \"" << runpath << "\"\n";
         }
+        os << indent << "  \"" << toDestDirPath << "\")\n";
       }
     }
   } else {
@@ -825,7 +846,7 @@ void cmInstallTargetGenerator::AddUniversalInstallRule(
     return;
   }
 
-  cmProp xcodeVersion = mf->GetDefinition("XCODE_VERSION");
+  cmValue xcodeVersion = mf->GetDefinition("XCODE_VERSION");
   if (!xcodeVersion ||
       cmSystemTools::VersionCompareGreater("6", *xcodeVersion)) {
     return;
index 32395d1..0974eea 100644 (file)
@@ -8,6 +8,7 @@
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
+#include "cmValue.h"
 
 cmInstalledFile::cmInstalledFile() = default;
 
index 2914046..1ec071b 100644 (file)
@@ -62,7 +62,7 @@ static void AddLinkDir(cmMakefile& mf, std::string const& dir,
       case cmPolicies::WARN:
         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0015);
         mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
-        break;
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         // OLD behavior does not convert
         break;
index 4e50d70..62e7ef4 100644 (file)
@@ -32,7 +32,11 @@ bool operator<(cmLinkItem const& l, cmLinkItem const& r)
 {
   // Order among targets.
   if (l.Target && r.Target) {
-    return l.Target < r.Target;
+    if (l.Target != r.Target) {
+      return l.Target < r.Target;
+    }
+    // Order identical targets via cross-config.
+    return l.Cross < r.Cross;
   }
   // Order targets before strings.
   if (l.Target) {
@@ -42,10 +46,10 @@ bool operator<(cmLinkItem const& l, cmLinkItem const& r)
     return false;
   }
   // Order among strings.
-  if (l.String < r.String) {
-    return true;
+  if (l.String != r.String) {
+    return l.String < r.String;
   }
-  // Order among cross-config.
+  // Order identical strings via cross-config.
   return l.Cross < r.Cross;
 }
 
index 2ffff96..43f161b 100644 (file)
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
+#include "cmValue.h"
 
 class cmOutputConverter;
 
@@ -177,7 +177,7 @@ bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg,
     return false;
   }
 
-  if (cmProp resolveDeviceSymbols =
+  if (cmValue resolveDeviceSymbols =
         target.GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
     // If CUDA_RESOLVE_DEVICE_SYMBOLS has been explicitly set we need
     // to honor the value no matter what it is.
index 09cd88e..7d42fc8 100644 (file)
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmStringReplaceHelper.h"
 #include "cmSubcommandTable.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 namespace {
 
@@ -46,7 +46,7 @@ bool GetIndexArg(const std::string& arg, int* idx, cmMakefile& mf)
           cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0121),
                    " Invalid list index \"", arg, "\".");
         mf.IssueMessage(MessageType::AUTHOR_WARNING, warn);
-        break;
+        CM_FALLTHROUGH;
       }
       case cmPolicies::OLD:
         // OLD behavior is to allow compatibility, so just ignore the
@@ -79,7 +79,7 @@ bool GetListString(std::string& listString, const std::string& var,
                    const cmMakefile& makefile)
 {
   // get the old value
-  cmProp cacheValue = makefile.GetDefinition(var);
+  cmValue cacheValue = makefile.GetDefinition(var);
   if (!cacheValue) {
     return false;
   }
index 4f7c959..2e444f2 100644 (file)
@@ -548,7 +548,7 @@ void cmListFileBacktrace::PrintTitle(std::ostream& out) const
   }
   cmListFileContext lfc = this->TopEntry->Context;
   cmStateSnapshot bottom = this->GetBottom();
-  if (!bottom.GetState()->GetIsInTryCompile()) {
+  if (bottom.GetState()->GetProjectKind() == cmState::ProjectKind::Normal) {
     lfc.FilePath = cmSystemTools::RelativeIfUnder(
       bottom.GetState()->GetSourceDirectory(), lfc.FilePath);
   }
@@ -579,7 +579,7 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const
       out << "Call Stack (most recent call first):\n";
     }
     cmListFileContext lfc = cur->Context;
-    if (!bottom.GetState()->GetIsInTryCompile()) {
+    if (bottom.GetState()->GetProjectKind() == cmState::ProjectKind::Normal) {
       lfc.FilePath = cmSystemTools::RelativeIfUnder(
         bottom.GetState()->GetSourceDirectory(), lfc.FilePath);
     }
index 211525a..eca7a9e 100644 (file)
@@ -8,11 +8,11 @@
 #include "cmGeneratorTarget.h"
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
+#include "cmValue.h"
 
 class cmGlobalGenerator;
 
@@ -82,7 +82,7 @@ std::string cmLocalCommonGenerator::GetTargetFortranFlags(
   // If there is a separate module path flag then duplicate the
   // include path with it.  This compiler does not search the include
   // path for modules.
-  if (cmProp modpath_flag =
+  if (cmValue modpath_flag =
         this->Makefile->GetDefinition("CMAKE_Fortran_MODPATH_FLAG")) {
     std::vector<std::string> includes;
     this->GetIncludeDirectories(includes, target, "C", config);
index 3b282de..fc5e6e5 100644 (file)
@@ -37,7 +37,6 @@
 #include "cmInstallTargetGenerator.h"
 #include "cmLinkLineComputer.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
 #include "cmSourceFileLocation.h"
@@ -50,6 +49,7 @@
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTestGenerator.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 #include "cmake.h"
 
@@ -107,10 +107,9 @@ cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
   {
     std::vector<std::string> cpath;
     cmSystemTools::GetPath(cpath, "CPATH");
-    for (std::string& cp : cpath) {
+    for (std::string const& cp : cpath) {
       if (cmSystemTools::FileIsFullPath(cp)) {
-        cp = cmSystemTools::CollapseFullPath(cp);
-        this->EnvCPATH.emplace(std::move(cp));
+        this->EnvCPATH.emplace_back(cmSystemTools::CollapseFullPath(cp));
       }
     }
   }
@@ -118,21 +117,21 @@ cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
   std::vector<std::string> enabledLanguages =
     this->GetState()->GetEnabledLanguages();
 
-  if (cmProp sysrootCompile =
+  if (cmValue sysrootCompile =
         this->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
     this->CompilerSysroot = *sysrootCompile;
   } else {
     this->CompilerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
   }
 
-  if (cmProp sysrootLink =
+  if (cmValue sysrootLink =
         this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
     this->LinkerSysroot = *sysrootLink;
   } else {
     this->LinkerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
   }
 
-  if (cmProp appleArchSysroots =
+  if (cmValue appleArchSysroots =
         this->Makefile->GetDefinition("CMAKE_APPLE_ARCH_SYSROOTS")) {
     std::string const& appleArchs =
       this->Makefile->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES");
@@ -222,7 +221,7 @@ void cmLocalGenerator::ComputeObjectMaxPath()
 #else
   this->ObjectPathMax = 1000;
 #endif
-  cmProp plen = this->Makefile->GetDefinition("CMAKE_OBJECT_PATH_MAX");
+  cmValue plen = this->Makefile->GetDefinition("CMAKE_OBJECT_PATH_MAX");
   if (cmNonempty(plen)) {
     unsigned int pmax;
     if (sscanf(plen->c_str(), "%u", &pmax) == 1) {
@@ -330,12 +329,12 @@ void cmLocalGenerator::GenerateTestFiles()
     fout << "set(CTEST_RESOURCE_SPEC_FILE \"" << resourceSpecFile << "\")\n";
   }
 
-  cmProp testIncludeFile = this->Makefile->GetProperty("TEST_INCLUDE_FILE");
+  cmValue testIncludeFile = this->Makefile->GetProperty("TEST_INCLUDE_FILE");
   if (testIncludeFile) {
     fout << "include(\"" << *testIncludeFile << "\")\n";
   }
 
-  cmProp testIncludeFiles = this->Makefile->GetProperty("TEST_INCLUDE_FILES");
+  cmValue testIncludeFiles = this->Makefile->GetProperty("TEST_INCLUDE_FILES");
   if (testIncludeFiles) {
     std::vector<std::string> includesList = cmExpandedList(*testIncludeFiles);
     for (std::string const& i : includesList) {
@@ -359,9 +358,9 @@ void cmLocalGenerator::GenerateTestFiles()
   }
 
   // Add directory labels property
-  cmProp directoryLabels =
+  cmValue directoryLabels =
     this->Makefile->GetDefinition("CMAKE_DIRECTORY_LABELS");
-  cmProp labels = this->Makefile->GetProperty("LABELS");
+  cmValue labels = this->Makefile->GetProperty("LABELS");
 
   if (labels || directoryLabels) {
     fout << "set_directory_properties(PROPERTIES LABELS ";
@@ -426,27 +425,26 @@ void cmLocalGenerator::ProcessEvaluationFiles(
 void cmLocalGenerator::GenerateInstallRules()
 {
   // Compute the install prefix.
-  const char* prefix =
-    cmToCStr(this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX"));
+  cmValue installPrefix =
+    this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
+  std::string prefix = installPrefix;
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
-  std::string prefix_win32;
-  if (!prefix) {
-    if (!cmSystemTools::GetEnv("SystemDrive", prefix_win32)) {
-      prefix_win32 = "C:";
+  if (!installPrefix) {
+    if (!cmSystemTools::GetEnv("SystemDrive", prefix)) {
+      prefix = "C:";
     }
-    cmProp project_name = this->Makefile->GetDefinition("PROJECT_NAME");
+    cmValue project_name = this->Makefile->GetDefinition("PROJECT_NAME");
     if (cmNonempty(project_name)) {
-      prefix_win32 += "/Program Files/";
-      prefix_win32 += *project_name;
+      prefix += "/Program Files/";
+      prefix += *project_name;
     } else {
-      prefix_win32 += "/InstalledCMakeProject";
+      prefix += "/InstalledCMakeProject";
     }
-    prefix = prefix_win32.c_str();
   }
 #elif defined(__HAIKU__)
   char dir[B_PATH_NAME_LENGTH];
-  if (!prefix) {
+  if (!installPrefix) {
     if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) ==
         B_OK) {
       prefix = dir;
@@ -455,13 +453,13 @@ void cmLocalGenerator::GenerateInstallRules()
     }
   }
 #else
-  if (!prefix) {
+  if (!installPrefix) {
     prefix = "/usr/local";
   }
 #endif
-  if (cmProp stagingPrefix =
+  if (cmValue stagingPrefix =
         this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX")) {
-    prefix = stagingPrefix->c_str();
+    prefix = *stagingPrefix;
   }
 
   // Compute the set of configurations.
@@ -541,7 +539,7 @@ void cmLocalGenerator::GenerateInstallRules()
   /* clang-format on */
 
   // Copy user-specified install options to the install code.
-  if (cmProp so_no_exe =
+  if (cmValue so_no_exe =
         this->Makefile->GetDefinition("CMAKE_INSTALL_SO_NO_EXE")) {
     /* clang-format off */
     fout <<
@@ -554,7 +552,7 @@ void cmLocalGenerator::GenerateInstallRules()
   }
 
   // Copy cmake cross compile state to install code.
-  if (cmProp crosscompiling =
+  if (cmValue crosscompiling =
         this->Makefile->GetDefinition("CMAKE_CROSSCOMPILING")) {
     /* clang-format off */
     fout <<
@@ -567,7 +565,7 @@ void cmLocalGenerator::GenerateInstallRules()
   }
 
   // Write default directory permissions.
-  if (cmProp defaultDirPermissions = this->Makefile->GetDefinition(
+  if (cmValue defaultDirPermissions = this->Makefile->GetDefinition(
         "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS")) {
     /* clang-format off */
     fout <<
@@ -583,7 +581,7 @@ void cmLocalGenerator::GenerateInstallRules()
   // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM so that
   // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)`
   // has same platform variable as when running cmake
-  if (cmProp platform = this->Makefile->GetDefinition(
+  if (cmValue platform = this->Makefile->GetDefinition(
         "CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM")) {
     /* clang-format off */
     fout <<
@@ -599,7 +597,7 @@ void cmLocalGenerator::GenerateInstallRules()
   // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL so that
   // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)`
   // has same tool selected as when running cmake
-  if (cmProp command =
+  if (cmValue command =
         this->Makefile->GetDefinition("CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL")) {
     /* clang-format off */
     fout <<
@@ -615,7 +613,7 @@ void cmLocalGenerator::GenerateInstallRules()
   // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND so that
   // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)`
   // has same path to the tool as when running cmake
-  if (cmProp command = this->Makefile->GetDefinition(
+  if (cmValue command = this->Makefile->GetDefinition(
         "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND")) {
     /* clang-format off */
     fout <<
@@ -633,7 +631,7 @@ void cmLocalGenerator::GenerateInstallRules()
   // CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND has consistent
   // logic to fallback to CMAKE_OBJDUMP when `objdump` is
   // not on the path
-  if (cmProp command = this->Makefile->GetDefinition("CMAKE_OBJDUMP")) {
+  if (cmValue command = this->Makefile->GetDefinition("CMAKE_OBJDUMP")) {
     /* clang-format off */
     fout <<
       "# Set default install directory permissions.\n"
@@ -826,8 +824,8 @@ cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const
   return this->Makefile->GetStateSnapshot();
 }
 
-cmProp cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
-                                         const std::string& prop)
+cmValue cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
+                                          const std::string& prop)
 {
   if (target) {
     return target->GetProperty(prop);
@@ -859,36 +857,39 @@ std::string cmLocalGenerator::GetIncludeFlags(
 
   std::string const& includeFlag =
     this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_", lang));
-  const char* sep = cmToCStr(
-    this->Makefile->GetDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_SEP_", lang)));
   bool quotePaths = false;
   if (this->Makefile->GetDefinition("CMAKE_QUOTE_INCLUDE_PATHS")) {
     quotePaths = true;
   }
+  std::string sep = " ";
   bool repeatFlag = true;
   // should the include flag be repeated like ie. -IA -IB
-  if (!sep) {
-    sep = " ";
-  } else {
+  if (cmValue incSep = this->Makefile->GetDefinition(
+        cmStrCat("CMAKE_INCLUDE_FLAG_SEP_", lang))) {
     // if there is a separator then the flag is not repeated but is only
     // given once i.e.  -classpath a:b:c
+    sep = incSep;
     repeatFlag = false;
   }
 
   // Support special system include flag if it is available and the
   // normal flag is repeated for each directory.
-  cmProp sysIncludeFlag = nullptr;
+  cmValue sysIncludeFlag = nullptr;
+  cmValue sysIncludeFlagWarning = nullptr;
   if (repeatFlag) {
     sysIncludeFlag = this->Makefile->GetDefinition(
       cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang));
+    sysIncludeFlagWarning = this->Makefile->GetDefinition(
+      cmStrCat("_CMAKE_INCLUDE_SYSTEM_FLAG_", lang, "_WARNING"));
   }
 
-  cmProp fwSearchFlag = this->Makefile->GetDefinition(
+  cmValue fwSearchFlag = this->Makefile->GetDefinition(
     cmStrCat("CMAKE_", lang, "_FRAMEWORK_SEARCH_FLAG"));
-  cmProp sysFwSearchFlag = this->Makefile->GetDefinition(
+  cmValue sysFwSearchFlag = this->Makefile->GetDefinition(
     cmStrCat("CMAKE_", lang, "_SYSTEM_FRAMEWORK_SEARCH_FLAG"));
 
   bool flagUsed = false;
+  bool sysIncludeFlagUsed = false;
   std::set<std::string> emitted;
 #ifdef __APPLE__
   emitted.insert("/System/Library/Frameworks");
@@ -915,6 +916,7 @@ std::string cmLocalGenerator::GetIncludeFlags(
       if (sysIncludeFlag && target &&
           target->IsSystemIncludeDirectory(i, config, lang)) {
         includeFlags << *sysIncludeFlag;
+        sysIncludeFlagUsed = true;
       } else {
         includeFlags << includeFlag;
       }
@@ -931,6 +933,9 @@ std::string cmLocalGenerator::GetIncludeFlags(
     }
     includeFlags << sep;
   }
+  if (sysIncludeFlagUsed && sysIncludeFlagWarning) {
+    includeFlags << *sysIncludeFlagWarning;
+  }
   std::string flags = includeFlags.str();
   // remove trailing separators
   if ((sep[0] != ' ') && !flags.empty() && flags.back() == sep[0]) {
@@ -956,10 +961,10 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags,
 {
   std::string langFlagRegexVar = cmStrCat("CMAKE_", lang, "_FLAG_REGEX");
 
-  if (cmProp langFlagRegexStr =
+  if (cmValue langFlagRegexStr =
         this->Makefile->GetDefinition(langFlagRegexVar)) {
     // Filter flags acceptable to this language.
-    if (cmProp targetFlags = target->GetProperty("COMPILE_FLAGS")) {
+    if (cmValue targetFlags = target->GetProperty("COMPILE_FLAGS")) {
       std::vector<std::string> opts;
       cmSystemTools::ParseWindowsCommandLine(targetFlags->c_str(), opts);
       // Re-escape these flags since COMPILE_FLAGS were already parsed
@@ -977,7 +982,7 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags,
                                langFlagRegexStr->c_str());
   } else {
     // Use all flags.
-    if (cmProp targetFlags = target->GetProperty("COMPILE_FLAGS")) {
+    if (cmValue targetFlags = target->GetProperty("COMPILE_FLAGS")) {
       // COMPILE_FLAGS are not escaped for historical reasons.
       std::string compileFlags;
       this->AppendFlags(compileFlags, *targetFlags);
@@ -993,7 +998,7 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags,
 
   cmStandardLevelResolver standardResolver(this->Makefile);
   for (auto const& it : target->GetMaxLanguageStandards()) {
-    cmProp standard = target->GetLanguageStandard(it.first, config);
+    cmValue standard = target->GetLanguageStandard(it.first, config);
     if (!standard) {
       continue;
     }
@@ -1024,7 +1029,7 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags,
 
   // Add compile flag for the MSVC compiler only.
   cmMakefile* mf = this->GetMakefile();
-  if (cmProp jmc =
+  if (cmValue jmc =
         mf->GetDefinition("CMAKE_" + lang + "_COMPILE_OPTIONS_JMC")) {
 
     // Handle Just My Code debugging flags, /JMC.
@@ -1033,7 +1038,7 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags,
         cmGeneratorTarget::ManagedType::Managed) {
       // add /JMC flags if target property VS_JUST_MY_CODE_DEBUGGING is set
       // to ON
-      if (cmProp jmcExprGen =
+      if (cmValue jmcExprGen =
             target->GetProperty("VS_JUST_MY_CODE_DEBUGGING")) {
         std::string isJMCEnabled =
           cmGeneratorExpression::Evaluate(*jmcExprGen, this, config);
@@ -1239,19 +1244,31 @@ std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit(
     }
   }
 
+  bool const isCorCxx = (lang == "C" || lang == "CXX");
+
+  // Resolve symlinks in CPATH for comparison with resolved include paths.
+  // We do this here instead of when EnvCPATH is populated in case symlinks
+  // on disk have changed in the meantime.
+  std::set<std::string> resolvedEnvCPATH;
+  if (isCorCxx) {
+    for (std::string const& i : this->EnvCPATH) {
+      resolvedEnvCPATH.emplace(this->GlobalGenerator->GetRealPath(i));
+    }
+  }
+
   // Checks if this is not an excluded (implicit) include directory.
-  auto notExcluded = [this, &implicitSet, &implicitExclude,
-                      &lang](std::string const& dir) {
-    return (
-      // Do not exclude directories that are not in an excluded set.
-      ((!cm::contains(implicitSet, this->GlobalGenerator->GetRealPath(dir))) &&
-       (!cm::contains(implicitExclude, dir)))
+  auto notExcluded = [this, &implicitSet, &implicitExclude, &resolvedEnvCPATH,
+                      isCorCxx](std::string const& dir) -> bool {
+    std::string const& real_dir = this->GlobalGenerator->GetRealPath(dir);
+    return
+      // Do not exclude directories that are not in any excluded set.
+      !(cm::contains(implicitSet, real_dir) ||
+        cm::contains(implicitExclude, dir))
       // Do not exclude entries of the CPATH environment variable even though
       // they are implicitly searched by the compiler.  They are meant to be
       // user-specified directories that can be re-ordered or converted to
       // -isystem without breaking real compiler builtin headers.
-      ||
-      ((lang == "C" || lang == "CXX") && cm::contains(this->EnvCPATH, dir)));
+      || (isCorCxx && cm::contains(resolvedEnvCPATH, real_dir));
   };
 
   // Get the target-specific include directories.
@@ -1480,7 +1497,7 @@ void cmLocalGenerator::GetTargetFlags(
         }
       }
 
-      cmProp targetLinkFlags = target->GetProperty("LINK_FLAGS");
+      cmValue targetLinkFlags = target->GetProperty("LINK_FLAGS");
       if (targetLinkFlags) {
         sharedLibFlags += *targetLinkFlags;
         sharedLibFlags += " ";
@@ -1560,7 +1577,7 @@ void cmLocalGenerator::GetTargetFlags(
         exeFlags += " ";
       }
 
-      cmProp targetLinkFlags = target->GetProperty("LINK_FLAGS");
+      cmValue targetLinkFlags = target->GetProperty("LINK_FLAGS");
       if (targetLinkFlags) {
         exeFlags += *targetLinkFlags;
         exeFlags += " ";
@@ -1656,7 +1673,7 @@ static std::string GetFrameworkFlags(const std::string& lang,
   }
 
   std::string fwSearchFlagVar = "CMAKE_" + lang + "_FRAMEWORK_SEARCH_FLAG";
-  cmProp fwSearchFlag = mf->GetDefinition(fwSearchFlagVar);
+  cmValue fwSearchFlag = mf->GetDefinition(fwSearchFlagVar);
   if (!cmNonempty(fwSearchFlag)) {
     return std::string();
   }
@@ -1765,7 +1782,7 @@ void cmLocalGenerator::OutputLinkLibraries(
   std::string linkLanguage = cli.GetLinkLanguage();
 
   std::string libPathFlag;
-  if (cmProp value = this->Makefile->GetDefinition(
+  if (cmValue value = this->Makefile->GetDefinition(
         "CMAKE_" + cli.GetLinkLanguage() + "_LIBRARY_PATH_FLAG")) {
     libPathFlag = *value;
   } else {
@@ -1774,7 +1791,7 @@ void cmLocalGenerator::OutputLinkLibraries(
   }
 
   std::string libPathTerminator;
-  if (cmProp value = this->Makefile->GetDefinition(
+  if (cmValue value = this->Makefile->GetDefinition(
         "CMAKE_" + cli.GetLinkLanguage() + "_LIBRARY_PATH_TERMINATOR")) {
     libPathTerminator = *value;
   } else {
@@ -1850,17 +1867,17 @@ std::string cmLocalGenerator::GetLinkLibsCMP0065(
 }
 
 bool cmLocalGenerator::AllAppleArchSysrootsAreTheSame(
-  const std::vector<std::string>& archs, const char* sysroot)
+  const std::vector<std::string>& archs, cmValue sysroot)
 {
   if (!sysroot) {
     return false;
   }
 
   return std::all_of(archs.begin(), archs.end(),
-                     [this, &sysroot](std::string const& arch) -> bool {
+                     [this, sysroot](std::string const& arch) -> bool {
                        std::string const& archSysroot =
                          this->AppleArchSysroots[arch];
-                       return cmIsOff(archSysroot) || archSysroot == sysroot;
+                       return cmIsOff(archSysroot) || sysroot == archSysroot;
                      });
 }
 
@@ -1885,15 +1902,15 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
       }
     }
 
-    cmProp sysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT");
+    cmValue sysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT");
     if (sysroot && *sysroot == "/") {
       sysroot = nullptr;
     }
     std::string sysrootFlagVar = "CMAKE_" + lang + "_SYSROOT_FLAG";
-    cmProp sysrootFlag = this->Makefile->GetDefinition(sysrootFlagVar);
+    cmValue sysrootFlag = this->Makefile->GetDefinition(sysrootFlagVar);
     if (cmNonempty(sysrootFlag)) {
       if (!this->AppleArchSysroots.empty() &&
-          !this->AllAppleArchSysrootsAreTheSame(archs, cmToCStr(sysroot))) {
+          !this->AllAppleArchSysrootsAreTheSame(archs, sysroot)) {
         for (std::string const& arch : archs) {
           std::string const& archSysroot = this->AppleArchSysroots[arch];
           if (cmIsOff(archSysroot)) {
@@ -1914,11 +1931,11 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
       }
     }
 
-    cmProp deploymentTarget =
+    cmValue deploymentTarget =
       this->Makefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
     std::string deploymentTargetFlagVar =
       "CMAKE_" + lang + "_OSX_DEPLOYMENT_TARGET_FLAG";
-    cmProp deploymentTargetFlag =
+    cmValue deploymentTargetFlag =
       this->Makefile->GetDefinition(deploymentTargetFlagVar);
     if (cmNonempty(deploymentTargetFlag) && cmNonempty(deploymentTarget)) {
       flags += " ";
@@ -1943,11 +1960,11 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
   std::string compilerSimulateId = this->Makefile->GetSafeDefinition(
     cmStrCat("CMAKE_", lang, "_SIMULATE_ID"));
   if (lang == "Swift") {
-    if (cmProp v = target->GetProperty("Swift_LANGUAGE_VERSION")) {
-      if (cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
-                                        cmToCStr(this->Makefile->GetDefinition(
-                                          "CMAKE_Swift_COMPILER_VERSION")),
-                                        "4.2")) {
+    if (cmValue v = target->GetProperty("Swift_LANGUAGE_VERSION")) {
+      if (cmSystemTools::VersionCompare(
+            cmSystemTools::OP_GREATER_EQUAL,
+            this->Makefile->GetDefinition("CMAKE_Swift_COMPILER_VERSION"),
+            "4.2")) {
         this->AppendFlags(flags, "-swift-version " + *v);
       }
     }
@@ -1974,7 +1991,7 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
 
   // Add VFS Overlay for Clang compilers
   if (compiler == "Clang") {
-    if (cmProp vfsOverlay =
+    if (cmValue vfsOverlay =
           this->Makefile->GetDefinition("CMAKE_CLANG_VFS_OVERLAY")) {
       if (compilerSimulateId == "MSVC") {
         this->AppendCompileOptions(
@@ -1989,10 +2006,10 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
   }
   // Add MSVC runtime library flags.  This is activated by the presence
   // of a default selection whether or not it is overridden by a property.
-  cmProp msvcRuntimeLibraryDefault =
+  cmValue msvcRuntimeLibraryDefault =
     this->Makefile->GetDefinition("CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT");
   if (cmNonempty(msvcRuntimeLibraryDefault)) {
-    cmProp msvcRuntimeLibraryValue =
+    cmValue msvcRuntimeLibraryValue =
       target->GetProperty("MSVC_RUNTIME_LIBRARY");
     if (!msvcRuntimeLibraryValue) {
       msvcRuntimeLibraryValue = msvcRuntimeLibraryDefault;
@@ -2000,7 +2017,7 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
     std::string const msvcRuntimeLibrary = cmGeneratorExpression::Evaluate(
       *msvcRuntimeLibraryValue, this, config, target);
     if (!msvcRuntimeLibrary.empty()) {
-      if (cmProp msvcRuntimeLibraryOptions = this->Makefile->GetDefinition(
+      if (cmValue msvcRuntimeLibraryOptions = this->Makefile->GetDefinition(
             "CMAKE_" + lang + "_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_" +
             msvcRuntimeLibrary)) {
         this->AppendCompileOptions(flags, *msvcRuntimeLibraryOptions);
@@ -2180,7 +2197,7 @@ void cmLocalGenerator::AddCompilerRequirementFlag(
   std::string const& optionFlagDef =
     standardResolver.GetCompileOptionDef(target, lang, config);
   if (!optionFlagDef.empty()) {
-    cmProp opt = target->Target->GetMakefile()->GetDefinition(optionFlagDef);
+    cmValue opt = target->Target->GetMakefile()->GetDefinition(optionFlagDef);
     if (opt) {
       std::vector<std::string> optVec = cmExpandedList(*opt);
       for (std::string const& i : optVec) {
@@ -2197,13 +2214,13 @@ static void AddVisibilityCompileOption(std::string& flags,
                                        std::string* warnCMP0063)
 {
   std::string compileOption = "CMAKE_" + lang + "_COMPILE_OPTIONS_VISIBILITY";
-  cmProp opt = lg->GetMakefile()->GetDefinition(compileOption);
+  cmValue opt = lg->GetMakefile()->GetDefinition(compileOption);
   if (!opt) {
     return;
   }
   std::string flagDefine = lang + "_VISIBILITY_PRESET";
 
-  cmProp prop = target->GetProperty(flagDefine);
+  cmValue prop = target->GetProperty(flagDefine);
   if (!prop) {
     return;
   }
@@ -2233,7 +2250,7 @@ static void AddInlineVisibilityCompileOption(std::string& flags,
 {
   std::string compileOption =
     cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN");
-  cmProp opt = lg->GetMakefile()->GetDefinition(compileOption);
+  cmValue opt = lg->GetMakefile()->GetDefinition(compileOption);
   if (!opt) {
     return;
   }
@@ -2430,7 +2447,7 @@ void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target)
     return;
   }
 
-  cmProp ispcHeaderSuffixProp = target->GetProperty("ISPC_HEADER_SUFFIX");
+  cmValue ispcHeaderSuffixProp = target->GetProperty("ISPC_HEADER_SUFFIX");
   assert(ispcHeaderSuffixProp);
 
   std::vector<std::string> ispcArchSuffixes =
@@ -2443,7 +2460,7 @@ void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target)
 
     std::string rootObjectDir = target->GetObjectDirectory(config);
     std::string headerDir = rootObjectDir;
-    if (cmProp prop = target->GetProperty("ISPC_HEADER_DIRECTORY")) {
+    if (cmValue prop = target->GetProperty("ISPC_HEADER_DIRECTORY")) {
       headerDir = cmSystemTools::CollapseFullPath(
         cmStrCat(this->GetBinaryDirectory(), '/', *prop));
     }
@@ -2493,6 +2510,16 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
     static const std::array<std::string, 4> langs = { { "C", "CXX", "OBJC",
                                                         "OBJCXX" } };
 
+    bool haveAnyPch = false;
+    if (this->GetGlobalGenerator()->IsXcode()) {
+      for (const std::string& lang : langs) {
+        const std::string pchHeader = target->GetPchHeader(config, lang, "");
+        if (!pchHeader.empty()) {
+          haveAnyPch = true;
+        }
+      }
+    }
+
     for (const std::string& lang : langs) {
       auto langSources = std::count_if(
         sources.begin(), sources.end(), [lang](cmSourceFile* sf) {
@@ -2533,17 +2560,22 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
         const std::string pchHeader = target->GetPchHeader(config, lang, arch);
 
         if (pchSource.empty() || pchHeader.empty()) {
+          if (this->GetGlobalGenerator()->IsXcode() && haveAnyPch) {
+            for (auto* sf : sources) {
+              sf->SetProperty("SKIP_PRECOMPILE_HEADERS", "ON");
+            }
+          }
           continue;
         }
 
-        const std::string pchExtension =
-          this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
+        cmValue pchExtension =
+          this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
 
-        if (pchExtension.empty()) {
+        if (pchExtension.IsEmpty()) {
           continue;
         }
 
-        cmProp ReuseFrom =
+        cmValue ReuseFrom =
           target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
 
         auto* pch_sf = this->Makefile->GetOrCreateSource(
@@ -2590,8 +2622,8 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
 
                 // MSVC 2008 is producing both .pdb and .idb files with /Zi.
                 bool msvc2008OrLess =
-                  cmSystemTools::VersionCompare(
-                    cmSystemTools::OP_LESS, compilerVersion.c_str(), "16.0") &&
+                  cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
+                                                compilerVersion, "16.0") &&
                   compilerId == "MSVC";
                 // but not when used via toolset -Tv90
                 if (this->Makefile->GetSafeDefinition(
@@ -2622,7 +2654,8 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
                   cmStrCat(" ",
                            this->ConvertToOutputFormat(pchSourceObj, SHELL)),
                   true);
-              } else {
+              } else if (reuseTarget->GetType() ==
+                         cmStateEnums::OBJECT_LIBRARY) {
                 target->Target->AppendProperty(
                   "INTERFACE_LINK_LIBRARIES",
                   cmStrCat("$<$<CONFIG:", config,
@@ -2630,7 +2663,7 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
               }
             }
           } else {
-            pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
+            pch_sf->SetProperty("PCH_EXTENSION", pchExtension);
           }
 
           // Add pchHeader to source files, which will
@@ -2665,8 +2698,8 @@ void cmLocalGenerator::CopyPchCompilePdb(
     cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
              target->GetName(), ".dir/");
 
-  const std::string copy_script =
-    cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake");
+  const std::string copy_script = cmStrCat(
+    target_compile_pdb_dir, "copy_idb_pdb_", config.c_str(), ".cmake");
   cmGeneratedFileStream file(copy_script);
 
   file << "# CMake generated file\n";
@@ -2721,7 +2754,7 @@ void cmLocalGenerator::CopyPchCompilePdb(
   bool stdPipesUTF8 = true;
 
   auto configGenex = [&](cm::string_view expr) -> std::string {
-    if (this->GetGlobalGenerator()->IsVisualStudio()) {
+    if (this->GetGlobalGenerator()->IsMultiConfig()) {
       return cmStrCat("$<$<CONFIG:", config, ">:", expr, ">");
     }
     return std::string(expr);
@@ -2740,8 +2773,8 @@ void cmLocalGenerator::CopyPchCompilePdb(
   std::vector<std::string> no_byproducts;
 
   std::vector<std::string> outputs;
-  outputs.push_back(
-    cmStrCat(target_compile_pdb_dir, pdb_prefix, ReuseFrom, ".pdb"));
+  outputs.push_back(configGenex(
+    cmStrCat(target_compile_pdb_dir, pdb_prefix, ReuseFrom, ".pdb")));
 
   if (this->GetGlobalGenerator()->IsVisualStudio()) {
     this->AddCustomCommandToTarget(
@@ -2771,13 +2804,13 @@ inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf,
                                  std::string const& filename)
 {
   target->AddSourceFileToUnityBatch(sf->ResolveFullPath());
-  sf->SetProperty("UNITY_SOURCE_FILE", filename.c_str());
+  sf->SetProperty("UNITY_SOURCE_FILE", filename);
 }
 }
 
 void cmLocalGenerator::IncludeFileInUnitySources(
   cmGeneratedFileStream& unity_file, std::string const& sf_full_path,
-  cmProp beforeInclude, cmProp afterInclude, cmProp uniqueIdName) const
+  cmValue beforeInclude, cmValue afterInclude, cmValue uniqueIdName) const
 {
   if (cmNonempty(uniqueIdName)) {
     std::string pathToHash;
@@ -2815,14 +2848,14 @@ void cmLocalGenerator::IncludeFileInUnitySources(
 
 std::vector<std::string> cmLocalGenerator::AddUnityFilesModeAuto(
   cmGeneratorTarget* target, std::string const& lang,
-  std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
-  cmProp afterInclude, std::string const& filename_base, size_t batchSize)
+  std::vector<cmSourceFile*> const& filtered_sources, cmValue beforeInclude,
+  cmValue afterInclude, std::string const& filename_base, size_t batchSize)
 {
   if (batchSize == 0) {
     batchSize = filtered_sources.size();
   }
 
-  cmProp uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID");
+  cmValue uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID");
 
   std::vector<std::string> unity_files;
   for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0;
@@ -2858,8 +2891,8 @@ std::vector<std::string> cmLocalGenerator::AddUnityFilesModeAuto(
 
 std::vector<std::string> cmLocalGenerator::AddUnityFilesModeGroup(
   cmGeneratorTarget* target, std::string const& lang,
-  std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
-  cmProp afterInclude, std::string const& filename_base)
+  std::vector<cmSourceFile*> const& filtered_sources, cmValue beforeInclude,
+  cmValue afterInclude, std::string const& filename_base)
 {
   std::vector<std::string> unity_files;
 
@@ -2867,7 +2900,7 @@ std::vector<std::string> cmLocalGenerator::AddUnityFilesModeGroup(
   // without a group
   std::unordered_map<std::string, std::vector<cmSourceFile*>> explicit_mapping;
   for (cmSourceFile* sf : filtered_sources) {
-    if (cmProp value = sf->GetProperty("UNITY_GROUP")) {
+    if (cmValue value = sf->GetProperty("UNITY_GROUP")) {
       auto i = explicit_mapping.find(*value);
       if (i == explicit_mapping.end()) {
         std::vector<cmSourceFile*> sources{ sf };
@@ -2878,7 +2911,7 @@ std::vector<std::string> cmLocalGenerator::AddUnityFilesModeGroup(
     }
   }
 
-  cmProp uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID");
+  cmValue uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID");
 
   for (auto const& item : explicit_mapping) {
     auto const& name = item.first;
@@ -2925,15 +2958,15 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
   std::vector<cmSourceFile*> sources;
   target->GetSourceFiles(sources, config);
 
-  cmProp batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE");
+  cmValue batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE");
   const size_t unityBatchSize = batchSizeString
     ? static_cast<size_t>(std::atoi(batchSizeString->c_str()))
     : 0;
 
-  cmProp beforeInclude =
+  cmValue beforeInclude =
     target->GetProperty("UNITY_BUILD_CODE_BEFORE_INCLUDE");
-  cmProp afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE");
-  cmProp unityMode = target->GetProperty("UNITY_BUILD_MODE");
+  cmValue afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE");
+  cmValue unityMode = target->GetProperty("UNITY_BUILD_MODE");
 
   for (std::string lang : { "C", "CXX" }) {
     std::vector<cmSourceFile*> filtered_sources;
@@ -2969,7 +3002,7 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
       auto* unity = this->GetMakefile()->GetOrCreateSource(file);
       target->AddSource(file, true);
       unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON");
-      unity->SetProperty("UNITY_SOURCE_FILE", file.c_str());
+      unity->SetProperty("UNITY_SOURCE_FILE", file);
     }
   }
 }
@@ -2993,7 +3026,7 @@ void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags,
   }
 
   const std::string name = "CMAKE_" + lang + "_LINK_OPTIONS_IPO";
-  cmProp rawFlagsList = this->Makefile->GetDefinition(name);
+  cmValue rawFlagsList = this->Makefile->GetDefinition(name);
   if (!rawFlagsList) {
     return;
   }
@@ -3039,6 +3072,30 @@ void cmLocalGenerator::AppendPositionIndependentLinkerFlags(
   }
 }
 
+bool cmLocalGenerator::AppendLWYUFlags(std::string& flags,
+                                       const cmGeneratorTarget* target,
+                                       const std::string& lang)
+{
+  auto useLWYU = target->GetPropertyAsBool("LINK_WHAT_YOU_USE") &&
+    (target->GetType() == cmStateEnums::TargetType::EXECUTABLE ||
+     target->GetType() == cmStateEnums::TargetType::SHARED_LIBRARY ||
+     target->GetType() == cmStateEnums::TargetType::MODULE_LIBRARY);
+
+  if (useLWYU) {
+    const auto& lwyuFlag = this->GetMakefile()->GetSafeDefinition(
+      cmStrCat("CMAKE_", lang, "_LINK_WHAT_YOU_USE_FLAG"));
+    useLWYU = !lwyuFlag.empty();
+
+    if (useLWYU) {
+      std::vector<BT<std::string>> lwyuOpts;
+      lwyuOpts.emplace_back(lwyuFlag);
+      this->AppendFlags(flags, target->ResolveLinkerWrapper(lwyuOpts, lang));
+    }
+  }
+
+  return useLWYU;
+}
+
 void cmLocalGenerator::AppendCompileOptions(std::string& options,
                                             std::string const& options_list,
                                             const char* regex) const
@@ -3184,7 +3241,7 @@ void cmLocalGenerator::JoinDefines(const std::set<std::string>& defines,
   // Lookup the define flag for the current language.
   std::string dflag = "-D";
   if (!lang.empty()) {
-    cmProp df =
+    cmValue df =
       this->Makefile->GetDefinition(cmStrCat("CMAKE_", lang, "_DEFINE_FLAG"));
     if (cmNonempty(df)) {
       dflag = *df;
@@ -3231,7 +3288,7 @@ void cmLocalGenerator::AppendFeatureOptions(std::string& flags,
                                             const std::string& lang,
                                             const char* feature)
 {
-  cmProp optionList = this->Makefile->GetDefinition(
+  cmValue optionList = this->Makefile->GetDefinition(
     cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_", feature));
   if (optionList) {
     std::vector<std::string> options = cmExpandedList(*optionList);
@@ -3241,8 +3298,8 @@ void cmLocalGenerator::AppendFeatureOptions(std::string& flags,
   }
 }
 
-cmProp cmLocalGenerator::GetFeature(const std::string& feature,
-                                    const std::string& config)
+cmValue cmLocalGenerator::GetFeature(const std::string& feature,
+                                     const std::string& config)
 {
   std::string featureName = feature;
   // TODO: Define accumulation policy for features (prepend, append,
@@ -3253,7 +3310,7 @@ cmProp cmLocalGenerator::GetFeature(const std::string& feature,
   }
   cmStateSnapshot snp = this->StateSnapshot;
   while (snp.IsValid()) {
-    if (cmProp value = snp.GetDirectory().GetProperty(featureName)) {
+    if (cmValue value = snp.GetDirectory().GetProperty(featureName)) {
       return value;
     }
     snp = snp.GetBuildsystemDirectoryParent();
@@ -3318,7 +3375,7 @@ void cmLocalGenerator::GenerateTargetInstallRules(
     }
 
     // Include the user-specified pre-install script for this target.
-    if (cmProp preinstall = l->GetProperty("PRE_INSTALL_SCRIPT")) {
+    if (cmValue preinstall = l->GetProperty("PRE_INSTALL_SCRIPT")) {
       cmInstallScriptGenerator g(*preinstall, false, "", false, false);
       g.Generate(os, config, configurationTypes);
     }
@@ -3371,7 +3428,7 @@ void cmLocalGenerator::GenerateTargetInstallRules(
     }
 
     // Include the user-specified post-install script for this target.
-    if (cmProp postinstall = l->GetProperty("POST_INSTALL_SCRIPT")) {
+    if (cmValue postinstall = l->GetProperty("POST_INSTALL_SCRIPT")) {
       cmInstallScriptGenerator g(*postinstall, false, "", false, false);
       g.Generate(os, config, configurationTypes);
     }
@@ -3596,8 +3653,8 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget(
   // Ensure that for the CMakeFiles/<target>.dir/generated_source_file
   // we don't end up having:
   // CMakeFiles/<target>.dir/CMakeFiles/<target>.dir/generated_source_file.obj
-  cmProp unitySourceFile = source.GetProperty("UNITY_SOURCE_FILE");
-  cmProp pchExtension = source.GetProperty("PCH_EXTENSION");
+  cmValue unitySourceFile = source.GetProperty("UNITY_SOURCE_FILE");
+  cmValue pchExtension = source.GetProperty("PCH_EXTENSION");
   const bool isPchObject = objectName.find("cmake_pch") != std::string::npos;
   if (unitySourceFile || pchExtension || isPchObject) {
     if (pchExtension) {
@@ -3696,7 +3753,7 @@ KWIML_INT_uint64_t cmLocalGenerator::GetBackwardsCompatibility()
     unsigned int major = 0;
     unsigned int minor = 0;
     unsigned int patch = 0;
-    if (cmProp value =
+    if (cmValue value =
           this->Makefile->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY")) {
       switch (sscanf(value->c_str(), "%u.%u.%u", &major, &minor, &patch)) {
         case 2:
@@ -3723,8 +3780,9 @@ bool cmLocalGenerator::NeedBackwardsCompatibility_2_4()
   // variable.
   switch (this->GetPolicyStatus(cmPolicies::CMP0001)) {
     case cmPolicies::WARN:
-    // WARN is just OLD without warning because user code does not
-    // always affect whether this check is done.
+      // WARN is just OLD without warning because user code does not
+      // always affect whether this check is done.
+      CM_FALLTHROUGH;
     case cmPolicies::OLD:
       // Old behavior is to check the variable.
       break;
@@ -3791,7 +3849,7 @@ bool cmLocalGenerator::CheckDefinition(std::string const& define) const
 static void cmLGInfoProp(cmMakefile* mf, cmGeneratorTarget* target,
                          const std::string& prop)
 {
-  if (cmProp val = target->GetProperty(prop)) {
+  if (cmValue val = target->GetProperty(prop)) {
     mf->AddDefinition(prop, *val);
   }
 }
@@ -3801,7 +3859,7 @@ void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target,
                                               const std::string& fname)
 {
   // Find the Info.plist template.
-  cmProp in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST");
+  cmValue in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST");
   std::string inFile = cmNonempty(in) ? *in : "MacOSXBundleInfo.plist.in";
   if (!cmSystemTools::FileIsFullPath(inFile)) {
     std::string inMod = this->Makefile->GetModulesFile(inFile);
@@ -3840,7 +3898,7 @@ void cmLocalGenerator::GenerateFrameworkInfoPList(
   const std::string& fname)
 {
   // Find the Info.plist template.
-  cmProp in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST");
+  cmValue in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST");
   std::string inFile = cmNonempty(in) ? *in : "MacOSXFrameworkInfo.plist.in";
   if (!cmSystemTools::FileIsFullPath(inFile)) {
     std::string inMod = this->Makefile->GetModulesFile(inFile);
index 993280a..3614c84 100644 (file)
@@ -20,8 +20,8 @@
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmStateSnapshot.h"
+#include "cmValue.h"
 
 class cmCompiledGeneratorExpression;
 class cmComputeLinkInformation;
@@ -171,6 +171,8 @@ public:
                                             cmGeneratorTarget* target,
                                             const std::string& config,
                                             const std::string& lang);
+  bool AppendLWYUFlags(std::string& flags, const cmGeneratorTarget* target,
+                       const std::string& lang);
 
   enum class IncludePathStyle
   {
@@ -245,7 +247,7 @@ public:
   void AppendFeatureOptions(std::string& flags, const std::string& lang,
                             const char* feature);
 
-  cmProp GetFeature(const std::string& feature, const std::string& config);
+  cmValue GetFeature(const std::string& feature, const std::string& config);
 
   /** \brief Get absolute path to dependency \a name
    *
@@ -545,7 +547,7 @@ public:
   void CreateEvaluationFileOutputs(const std::string& config);
   void ProcessEvaluationFiles(std::vector<std::string>& generatedFiles);
 
-  cmProp GetRuleLauncher(cmGeneratorTarget* target, const std::string& prop);
+  cmValue GetRuleLauncher(cmGeneratorTarget* target, const std::string& prop);
 
 protected:
   // The default implementation ignores the IncludePathStyle and always
@@ -587,7 +589,7 @@ protected:
   std::string::size_type ObjectPathMax;
   std::set<std::string> ObjectMaxPathViolations;
 
-  std::set<std::string> EnvCPATH;
+  std::vector<std::string> EnvCPATH;
 
   using GeneratorTargetMap =
     std::unordered_map<std::string, cmGeneratorTarget*>;
@@ -649,7 +651,7 @@ private:
 
   void ComputeObjectMaxPath();
   bool AllAppleArchSysrootsAreTheSame(const std::vector<std::string>& archs,
-                                      const char* sysroot);
+                                      cmValue sysroot);
 
   void CopyPchCompilePdb(const std::string& config, cmGeneratorTarget* target,
                          const std::string& ReuseFrom,
@@ -657,16 +659,16 @@ private:
                          std::vector<std::string> const& extensions);
   void IncludeFileInUnitySources(cmGeneratedFileStream& unity_file,
                                  std::string const& sf_full_path,
-                                 cmProp beforeInclude, cmProp afterInclude,
-                                 cmProp uniqueIdName) const;
+                                 cmValue beforeInclude, cmValue afterInclude,
+                                 cmValue uniqueIdName) const;
   std::vector<std::string> AddUnityFilesModeAuto(
     cmGeneratorTarget* target, std::string const& lang,
-    std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
-    cmProp afterInclude, std::string const& filename_base, size_t batchSize);
+    std::vector<cmSourceFile*> const& filtered_sources, cmValue beforeInclude,
+    cmValue afterInclude, std::string const& filename_base, size_t batchSize);
   std::vector<std::string> AddUnityFilesModeGroup(
     cmGeneratorTarget* target, std::string const& lang,
-    std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
-    cmProp afterInclude, std::string const& filename_base);
+    std::vector<cmSourceFile*> const& filtered_sources, cmValue beforeInclude,
+    cmValue afterInclude, std::string const& filename_base);
 };
 
 #if !defined(CMAKE_BOOTSTRAP)
index e88f33c..8556fe6 100644 (file)
@@ -27,7 +27,6 @@
 #include "cmMessageType.h"
 #include "cmNinjaTargetGenerator.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
 #include "cmState.h"
@@ -35,6 +34,7 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 cmLocalNinjaGenerator::cmLocalNinjaGenerator(cmGlobalGenerator* gg,
@@ -279,7 +279,7 @@ void cmLocalNinjaGenerator::WriteNinjaRequiredVersion(std::ostream& os)
   std::string requiredVersion = cmGlobalNinjaGenerator::RequiredNinjaVersion();
 
   // Ninja generator uses the 'console' pool if available (>= 1.5)
-  if (this->GetGlobalNinjaGenerator()->SupportsConsolePool()) {
+  if (this->GetGlobalNinjaGenerator()->SupportsDirectConsole()) {
     requiredVersion =
       cmGlobalNinjaGenerator::RequiredNinjaVersionForConsolePool();
   }
@@ -311,7 +311,7 @@ void cmLocalNinjaGenerator::WritePools(std::ostream& os)
 {
   cmGlobalNinjaGenerator::WriteDivider(os);
 
-  cmProp jobpools =
+  cmValue jobpools =
     this->GetCMakeInstance()->GetState()->GetGlobalProperty("JOB_POOLS");
   if (!jobpools) {
     jobpools = this->GetMakefile()->GetDefinition("CMAKE_JOB_POOLS");
@@ -796,8 +796,9 @@ cmLocalNinjaGenerator::MakeCustomCommandGenerators(
 
   bool transformDepfile = false;
   switch (cc.GetCMP0116Status()) {
-    case cmPolicies::OLD:
     case cmPolicies::WARN:
+      CM_FALLTHROUGH;
+    case cmPolicies::OLD:
       break;
     case cmPolicies::REQUIRED_IF_USED:
     case cmPolicies::REQUIRED_ALWAYS:
@@ -869,7 +870,7 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements(
 std::string cmLocalNinjaGenerator::MakeCustomLauncher(
   cmCustomCommandGenerator const& ccg)
 {
-  cmProp property_value = this->Makefile->GetProperty("RULE_LAUNCH_CUSTOM");
+  cmValue property_value = this->Makefile->GetProperty("RULE_LAUNCH_CUSTOM");
 
   if (!cmNonempty(property_value)) {
     return std::string();
@@ -903,7 +904,7 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher(
 
 void cmLocalNinjaGenerator::AdditionalCleanFiles(const std::string& config)
 {
-  if (cmProp prop_value =
+  if (cmValue prop_value =
         this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) {
     std::vector<std::string> cleanFiles;
     {
index 0667c55..7e39b91 100644 (file)
@@ -33,7 +33,6 @@
 #include "cmMakefile.h"
 #include "cmMakefileTargetGenerator.h"
 #include "cmOutputConverter.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
@@ -43,6 +42,7 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTargetDepend.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 #include "cmake.h"
 
@@ -570,7 +570,7 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule(
 
   // Mark the rule as symbolic if requested.
   if (symbolic) {
-    if (cmProp sym =
+    if (cmValue sym =
           this->Makefile->GetDefinition("CMAKE_MAKE_SYMBOLIC_RULE")) {
       os << tgt << space << ": " << *sym << "\n";
     }
@@ -884,7 +884,7 @@ void cmLocalUnixMakefileGenerator3::AppendRuleDepend(
 {
   // Add a dependency on the rule file itself unless an option to skip
   // it is specifically enabled by the user or project.
-  cmProp nodep = this->Makefile->GetDefinition("CMAKE_SKIP_RULE_DEPENDENCY");
+  cmValue nodep = this->Makefile->GetDefinition("CMAKE_SKIP_RULE_DEPENDENCY");
   if (cmIsOff(nodep)) {
     depends.emplace_back(ruleFileName);
   }
@@ -999,7 +999,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand(
 
       std::string launcher;
       // Short-circuit if there is no launcher.
-      cmProp val = this->GetRuleLauncher(target, "RULE_LAUNCH_CUSTOM");
+      cmValue val = this->GetRuleLauncher(target, "RULE_LAUNCH_CUSTOM");
       if (cmNonempty(val)) {
         // Expand rule variables referenced in the given launcher command.
         cmRulePlaceholderExpander::RuleVariables vars;
@@ -1125,7 +1125,7 @@ void cmLocalUnixMakefileGenerator3::AppendDirectoryCleanCommand(
 {
   std::vector<std::string> cleanFiles;
   // Look for additional files registered for cleaning in this directory.
-  if (cmProp prop_value =
+  if (cmValue prop_value =
         this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) {
     cmExpandList(cmGeneratorExpression::Evaluate(
                    *prop_value, this,
@@ -1501,18 +1501,18 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(
   // Lookup useful directory information.
   if (haveDirectoryInfo) {
     // Test whether we need to force Unix paths.
-    if (cmProp force = mf->GetDefinition("CMAKE_FORCE_UNIX_PATHS")) {
+    if (cmValue force = mf->GetDefinition("CMAKE_FORCE_UNIX_PATHS")) {
       if (!cmIsOff(force)) {
         cmSystemTools::SetForceUnixPaths(true);
       }
     }
 
     // Setup relative path top directories.
-    if (cmProp relativePathTopSource =
+    if (cmValue relativePathTopSource =
           mf->GetDefinition("CMAKE_RELATIVE_PATH_TOP_SOURCE")) {
       this->SetRelativePathTopSource(*relativePathTopSource);
     }
-    if (cmProp relativePathTopBinary =
+    if (cmValue relativePathTopBinary =
           mf->GetDefinition("CMAKE_RELATIVE_PATH_TOP_BINARY")) {
       this->SetRelativePathTopBinary(*relativePathTopBinary);
     }
@@ -1582,7 +1582,7 @@ void cmLocalUnixMakefileGenerator3::CheckMultipleOutputs(bool verbose)
   cmMakefile* mf = this->Makefile;
 
   // Get the string listing the multiple output pairs.
-  cmProp pairs_string = mf->GetDefinition("CMAKE_MULTIPLE_OUTPUT_PAIRS");
+  cmValue pairs_string = mf->GetDefinition("CMAKE_MULTIPLE_OUTPUT_PAIRS");
   if (!pairs_string) {
     return;
   }
@@ -1654,7 +1654,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules(
       std::vector<std::string> commands;
       std::vector<std::string> depends;
 
-      cmProp p = gt->GetProperty("EchoString");
+      cmValue p = gt->GetProperty("EchoString");
       const char* text = p ? p->c_str() : "Running external command ...";
       depends.reserve(gt->GetUtilities().size());
       for (BT<std::pair<std::string, bool>> const& u : gt->GetUtilities()) {
@@ -1754,7 +1754,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules(
   recursiveTarget = cmStrCat(this->GetCurrentBinaryDirectory(), "/preinstall");
   commands.clear();
   depends.clear();
-  cmProp noall =
+  cmValue noall =
     this->Makefile->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
   if (cmIsOff(noall)) {
     // Drive the build before installing.
@@ -1804,7 +1804,7 @@ void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf,
                                                       bool verbose)
 {
   // Get the list of target files to check
-  cmProp infoDef = mf->GetDefinition("CMAKE_DEPEND_INFO_FILES");
+  cmValue infoDef = mf->GetDefinition("CMAKE_DEPEND_INFO_FILES");
   if (!infoDef) {
     return;
   }
@@ -1903,7 +1903,7 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo(
 
       // Tell the dependency scanner what compiler is used.
       std::string cidVar = cmStrCat("CMAKE_", lang, "_COMPILER_ID");
-      cmProp cid = this->Makefile->GetDefinition(cidVar);
+      cmValue cid = this->Makefile->GetDefinition(cidVar);
       if (cmNonempty(cid)) {
         cmakefileStream << "set(CMAKE_" << lang << "_COMPILER_ID \"" << *cid
                         << "\")\n";
@@ -1960,11 +1960,11 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo(
     // Store include transform rule properties.  Write the directory
     // rules first because they may be overridden by later target rules.
     std::vector<std::string> transformRules;
-    if (cmProp xform =
+    if (cmValue xform =
           this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
       cmExpandList(*xform, transformRules);
     }
-    if (cmProp xform =
+    if (cmValue xform =
           target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
       cmExpandList(*xform, transformRules);
     }
index 14dd0ba..78aa7f9 100644 (file)
@@ -299,7 +299,7 @@ private:
     cmGeneratorTarget const* target)
   {
     return this->CommandsVisited[target];
-  };
+  }
 
   std::map<cmGeneratorTarget const*, std::set<cmSourceFile const*>>
     CommandsVisited;
index 151470b..5d3e11a 100644 (file)
@@ -69,7 +69,7 @@ void cmLocalVisualStudio7Generator::AddHelperCommands()
     if (!l->IsInBuildSystem()) {
       continue;
     }
-    cmProp path = l->GetProperty("EXTERNAL_MSPROJECT");
+    cmValue path = l->GetProperty("EXTERNAL_MSPROJECT");
     if (path) {
       this->ReadAndStoreExternalGUID(l->GetName(), path->c_str());
     }
@@ -402,6 +402,7 @@ cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[] = {
     cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
   { "PrecompiledHeaderThrough", "Yc", "Precompiled Header Name", "",
     cmVS7FlagTable::UserValueRequired },
+  { "UsePrecompiledHeader", "Y-", "Don't use precompiled header", "0", 0 },
   { "PrecompiledHeaderFile", "Fp", "Generated Precompiled Header", "",
     cmVS7FlagTable::UserValue },
   // The YX and Yu options are in a per-global-generator table because
@@ -566,7 +567,7 @@ public:
     } else {
       this->Stream << this->LG->EscapeForXML("\n");
     }
-    std::string script = this->LG->ConstructScript(ccg);
+    std::string script = this->LG->ConstructScript(ccg, unmanaged);
     this->Stream << this->LG->EscapeForXML(script);
   }
 
@@ -582,7 +583,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
   const std::string& libName, cmGeneratorTarget* target)
 {
   std::string mfcFlag;
-  if (cmProp p = this->Makefile->GetDefinition("CMAKE_MFC_FLAG")) {
+  if (cmValue p = this->Makefile->GetDefinition("CMAKE_MFC_FLAG")) {
     mfcFlag = cmGeneratorExpression::Evaluate(*p, this, configName);
   } else {
     mfcFlag = "0";
@@ -781,7 +782,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
   fout << "\t\t\t<Tool\n"
        << "\t\t\t\tName=\"" << tool << "\"\n";
   if (this->FortranProject) {
-    cmProp target_mod_dir = target->GetProperty("Fortran_MODULE_DIRECTORY");
+    cmValue target_mod_dir = target->GetProperty("Fortran_MODULE_DIRECTORY");
     std::string modDir;
     if (target_mod_dir) {
       modDir = this->MaybeRelativeToCurBinDir(*target_mod_dir);
@@ -938,7 +939,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
       " " + GetBuildTypeLinkerFlags("CMAKE_MODULE_LINKER_FLAGS", configName);
   }
 
-  cmProp targetLinkFlags = target->GetProperty("LINK_FLAGS");
+  cmValue targetLinkFlags = target->GetProperty("LINK_FLAGS");
   if (targetLinkFlags) {
     extraLinkOptions += " ";
     extraLinkOptions += *targetLinkFlags;
@@ -1077,7 +1078,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
         }
       }
       std::string stackVar = cmStrCat("CMAKE_", linkLanguage, "_STACK_SIZE");
-      cmProp stackVal = this->Makefile->GetDefinition(stackVar);
+      cmValue stackVal = this->Makefile->GetDefinition(stackVar);
       if (stackVal) {
         fout << "\t\t\t\tStackReserveSize=\"" << *stackVal << "\"\n";
       }
@@ -1168,7 +1169,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
              << "\"\n";
       }
       std::string stackVar = cmStrCat("CMAKE_", linkLanguage, "_STACK_SIZE");
-      cmProp stackVal = this->Makefile->GetDefinition(stackVar);
+      cmValue stackVal = this->Makefile->GetDefinition(stackVar);
       if (stackVal) {
         fout << "\t\t\t\tStackReserveSize=\"" << *stackVal << "\"";
       }
@@ -1209,8 +1210,8 @@ void cmLocalVisualStudio7Generator::OutputDeploymentDebuggerTool(
   std::ostream& fout, std::string const& config, cmGeneratorTarget* target)
 {
   if (this->WindowsCEProject) {
-    cmProp dir = target->GetProperty("DEPLOYMENT_REMOTE_DIRECTORY");
-    cmProp additionalFiles =
+    cmValue dir = target->GetProperty("DEPLOYMENT_REMOTE_DIRECTORY");
+    cmValue additionalFiles =
       target->GetProperty("DEPLOYMENT_ADDITIONAL_FILES");
 
     if (!dir && !additionalFiles) {
@@ -1447,12 +1448,12 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
       needfc = true;
     }
     const std::string COMPILE_FLAGS("COMPILE_FLAGS");
-    if (cmProp cflags = sf.GetProperty(COMPILE_FLAGS)) {
+    if (cmValue cflags = sf.GetProperty(COMPILE_FLAGS)) {
       fc.CompileFlags = genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS);
       needfc = true;
     }
     const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
-    if (cmProp coptions = sf.GetProperty(COMPILE_OPTIONS)) {
+    if (cmValue coptions = sf.GetProperty(COMPILE_OPTIONS)) {
       lg->AppendCompileOptions(
         fc.CompileFlags,
         genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
@@ -1504,25 +1505,25 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
       }
     }
     const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
-    if (cmProp cdefs = sf.GetProperty(COMPILE_DEFINITIONS)) {
+    if (cmValue cdefs = sf.GetProperty(COMPILE_DEFINITIONS)) {
       fc.CompileDefs = genexInterpreter.Evaluate(*cdefs, COMPILE_DEFINITIONS);
       needfc = true;
     }
     std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", configUpper);
-    if (cmProp ccdefs = sf.GetProperty(defPropName)) {
+    if (cmValue ccdefs = sf.GetProperty(defPropName)) {
       fc.CompileDefsConfig =
         genexInterpreter.Evaluate(*ccdefs, COMPILE_DEFINITIONS);
       needfc = true;
     }
 
     const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
-    if (cmProp cincs = sf.GetProperty(INCLUDE_DIRECTORIES)) {
+    if (cmValue cincs = sf.GetProperty(INCLUDE_DIRECTORIES)) {
       fc.IncludeDirs = genexInterpreter.Evaluate(*cincs, INCLUDE_DIRECTORIES);
       needfc = true;
     }
 
     // Check for extra object-file dependencies.
-    if (cmProp deps = sf.GetProperty("OBJECT_DEPENDS")) {
+    if (cmValue deps = sf.GetProperty("OBJECT_DEPENDS")) {
       std::vector<std::string> depends = cmExpandedList(*deps);
       const char* sep = "";
       for (const std::string& d : depends) {
@@ -1779,7 +1780,7 @@ void cmLocalVisualStudio7Generator::WriteCustomRule(
     }
 
     std::string comment = this->ConstructComment(ccg);
-    std::string script = this->ConstructScript(ccg);
+    std::string script = this->ConstructScript(ccg, unmanaged);
     if (this->FortranProject) {
       cmSystemTools::ReplaceString(script, "$(Configuration)", config);
     }
@@ -1897,9 +1898,9 @@ void cmLocalVisualStudio7Generator::WriteProjectSCC(std::ostream& fout,
 {
   // if we have all the required Source code control tags
   // then add that to the project
-  cmProp vsProjectname = target->GetProperty("VS_SCC_PROJECTNAME");
-  cmProp vsLocalpath = target->GetProperty("VS_SCC_LOCALPATH");
-  cmProp vsProvider = target->GetProperty("VS_SCC_PROVIDER");
+  cmValue vsProjectname = target->GetProperty("VS_SCC_PROJECTNAME");
+  cmValue vsLocalpath = target->GetProperty("VS_SCC_LOCALPATH");
+  cmValue vsProvider = target->GetProperty("VS_SCC_PROVIDER");
 
   if (vsProvider && vsLocalpath && vsProjectname) {
     /* clang-format off */
@@ -1908,7 +1909,7 @@ void cmLocalVisualStudio7Generator::WriteProjectSCC(std::ostream& fout,
          << "\tSccProvider=\"" << *vsProvider << "\"\n";
     /* clang-format on */
 
-    cmProp vsAuxPath = target->GetProperty("VS_SCC_AUXPATH");
+    cmValue vsAuxPath = target->GetProperty("VS_SCC_AUXPATH");
     if (vsAuxPath) {
       fout << "\tSccAuxPath=\"" << *vsAuxPath << "\"\n";
     }
@@ -1928,7 +1929,7 @@ void cmLocalVisualStudio7Generator::WriteProjectStartFortran(
        << "\tProjectCreator=\"Intel Fortran\"\n"
        << "\tVersion=\"" << gg->GetIntelProjectVersion() << "\"\n";
   /* clang-format on */
-  cmProp p = target->GetProperty("VS_KEYWORD");
+  cmValue p = target->GetProperty("VS_KEYWORD");
   const char* keyword = p ? p->c_str() : "Console Application";
   const char* projectType = 0;
   switch (target->GetType()) {
@@ -1990,14 +1991,14 @@ void cmLocalVisualStudio7Generator::WriteProjectStart(
        << "\tProjectType=\"Visual C++\"\n";
   /* clang-format on */
   fout << "\tVersion=\"" << (gg->GetVersion() / 10) << ".00\"\n";
-  cmProp p = target->GetProperty("PROJECT_LABEL");
+  cmValue p = target->GetProperty("PROJECT_LABEL");
   const std::string projLabel = p ? *p : libName;
   p = target->GetProperty("VS_KEYWORD");
   const std::string keyword = p ? *p : "Win32Proj";
   fout << "\tName=\"" << projLabel << "\"\n";
   fout << "\tProjectGUID=\"{" << gg->GetGUID(libName) << "}\"\n";
   this->WriteProjectSCC(fout, target);
-  if (cmProp targetFrameworkVersion =
+  if (cmValue targetFrameworkVersion =
         target->GetProperty("VS_DOTNET_TARGET_FRAMEWORK_VERSION")) {
     fout << "\tTargetFrameworkVersion=\"" << *targetFrameworkVersion << "\"\n";
   }
@@ -2142,7 +2143,7 @@ void cmLocalVisualStudio7Generator::ReadAndStoreExternalGUID(
   std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE");
   // save the GUID in the cache
   this->GlobalGenerator->GetCMakeInstance()->AddCacheEntry(
-    guidStoreName, parser.GUID.c_str(), "Stored GUID", cmStateEnums::INTERNAL);
+    guidStoreName, parser.GUID, "Stored GUID", cmStateEnums::INTERNAL);
 }
 
 std::string cmLocalVisualStudio7Generator::GetTargetDirectory(
index 002f484..4ed1dd9 100644 (file)
@@ -124,7 +124,8 @@ const char* cmLocalVisualStudioGenerator::GetReportErrorLabel() const
 }
 
 std::string cmLocalVisualStudioGenerator::ConstructScript(
-  cmCustomCommandGenerator const& ccg, const std::string& newline_text)
+  cmCustomCommandGenerator const& ccg, IsManaged isManaged,
+  const std::string& newline_text)
 {
   bool useLocal = this->CustomCommandUseLocal();
   std::string workingDirectory = ccg.GetWorkingDirectory();
@@ -171,8 +172,9 @@ std::string cmLocalVisualStudioGenerator::ConstructScript(
 
   // for visual studio IDE add extra stuff to the PATH
   // if CMAKE_MSVCIDE_RUN_PATH is set.
-  if (this->Makefile->GetDefinition("MSVC_IDE")) {
-    cmProp extraPath = this->Makefile->GetDefinition("CMAKE_MSVCIDE_RUN_PATH");
+  if (this->GetGlobalGenerator()->IsVisualStudio()) {
+    cmValue extraPath =
+      this->Makefile->GetDefinition("CMAKE_MSVCIDE_RUN_PATH");
     if (extraPath) {
       script += newline;
       newline = newline_text;
@@ -236,6 +238,14 @@ std::string cmLocalVisualStudioGenerator::ConstructScript(
     script += newline;
     script += "if %errorlevel% neq 0 goto ";
     script += this->GetReportErrorLabel();
+    if (isManaged == managed) {
+      // These aren't generated by default for C# projects.
+      script += newline;
+      script += this->GetReportErrorLabel();
+      script += newline;
+      script += "exit /b 0";
+      script += newline;
+    }
   }
 
   return script;
index 91fb6b0..0e7f63f 100644 (file)
@@ -31,7 +31,13 @@ public:
   virtual ~cmLocalVisualStudioGenerator();
 
   /** Construct a script from the given list of command lines.  */
+  enum IsManaged
+  {
+    unmanaged,
+    managed
+  };
   std::string ConstructScript(cmCustomCommandGenerator const& ccg,
+                              IsManaged isManaged,
                               const std::string& newline = "\n");
 
   /** Label to which to jump in a batch file after a failed step in a
index c970abe..83984f7 100644 (file)
@@ -190,7 +190,7 @@ void cmMakefile::MaybeWarnCMP0074(std::string const& pkg)
 {
   // Warn if a <pkg>_ROOT variable we may use is set.
   std::string const varName = pkg + "_ROOT";
-  cmProp var = this->GetDefinition(varName);
+  cmValue var = this->GetDefinition(varName);
   std::string env;
   cmSystemTools::GetEnv(varName, env);
 
@@ -212,59 +212,31 @@ void cmMakefile::MaybeWarnCMP0074(std::string const& pkg)
   }
 }
 
-cmStringRange cmMakefile::GetIncludeDirectoriesEntries() const
+cmBTStringRange cmMakefile::GetIncludeDirectoriesEntries() const
 {
   return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries();
 }
 
-cmBacktraceRange cmMakefile::GetIncludeDirectoriesBacktraces() const
-{
-  return this->StateSnapshot.GetDirectory()
-    .GetIncludeDirectoriesEntryBacktraces();
-}
-
-cmStringRange cmMakefile::GetCompileOptionsEntries() const
+cmBTStringRange cmMakefile::GetCompileOptionsEntries() const
 {
   return this->StateSnapshot.GetDirectory().GetCompileOptionsEntries();
 }
 
-cmBacktraceRange cmMakefile::GetCompileOptionsBacktraces() const
-{
-  return this->StateSnapshot.GetDirectory().GetCompileOptionsEntryBacktraces();
-}
-
-cmStringRange cmMakefile::GetCompileDefinitionsEntries() const
+cmBTStringRange cmMakefile::GetCompileDefinitionsEntries() const
 {
   return this->StateSnapshot.GetDirectory().GetCompileDefinitionsEntries();
 }
 
-cmBacktraceRange cmMakefile::GetCompileDefinitionsBacktraces() const
-{
-  return this->StateSnapshot.GetDirectory()
-    .GetCompileDefinitionsEntryBacktraces();
-}
-
-cmStringRange cmMakefile::GetLinkOptionsEntries() const
+cmBTStringRange cmMakefile::GetLinkOptionsEntries() const
 {
   return this->StateSnapshot.GetDirectory().GetLinkOptionsEntries();
 }
 
-cmBacktraceRange cmMakefile::GetLinkOptionsBacktraces() const
-{
-  return this->StateSnapshot.GetDirectory().GetLinkOptionsEntryBacktraces();
-}
-
-cmStringRange cmMakefile::GetLinkDirectoriesEntries() const
+cmBTStringRange cmMakefile::GetLinkDirectoriesEntries() const
 {
   return this->StateSnapshot.GetDirectory().GetLinkDirectoriesEntries();
 }
 
-cmBacktraceRange cmMakefile::GetLinkDirectoriesBacktraces() const
-{
-  return this->StateSnapshot.GetDirectory()
-    .GetLinkDirectoriesEntryBacktraces();
-}
-
 cmListFileBacktrace cmMakefile::GetBacktrace() const
 {
   return this->Backtrace;
@@ -428,7 +400,7 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
 
   // Check for maximum recursion depth.
   int depth = CMake_DEFAULT_RECURSION_LIMIT;
-  cmProp depthStr = this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH");
+  cmValue depthStr = this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH");
   if (depthStr) {
     std::istringstream s(*depthStr);
     int d;
@@ -614,7 +586,7 @@ void cmMakefile::IncludeScope::EnforceCMP0011()
 bool cmMakefile::ReadDependentFile(const std::string& filename,
                                    bool noPolicyScope)
 {
-  if (cmProp def = this->GetDefinition("CMAKE_CURRENT_LIST_FILE")) {
+  if (cmValue def = this->GetDefinition("CMAKE_CURRENT_LIST_FILE")) {
     this->AddDefinition("CMAKE_PARENT_LIST_FILE", *def);
   }
   std::string filenametoread = cmSystemTools::CollapseFullPath(
@@ -846,6 +818,7 @@ void cmMakefile::EnforceDirectoryLevelRules() const
         // version.
         this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
                                                msg.str(), this->Backtrace);
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         // OLD behavior is to use policy version 2.4 set in
         // cmListFileCache.
@@ -857,7 +830,7 @@ void cmMakefile::EnforceDirectoryLevelRules() const
         this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
                                                msg.str(), this->Backtrace);
         cmSystemTools::SetFatalErrorOccured();
-        return;
+        break;
     }
   }
 }
@@ -952,10 +925,9 @@ void cmMakefile::DoGenerate(cmLocalGenerator& lg)
 void cmMakefile::Generate(cmLocalGenerator& lg)
 {
   this->DoGenerate(lg);
-  cmProp oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
+  cmValue oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
   if (oldValue &&
-      cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue->c_str(),
-                                    "2.4")) {
+      cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue, "2.4")) {
     this->GetCMakeInstance()->IssueMessage(
       MessageType::FATAL_ERROR,
       "You have set CMAKE_BACKWARDS_COMPATIBILITY to a CMake version less "
@@ -1030,6 +1002,7 @@ cmTarget* cmMakefile::GetCustomCommandTarget(
       case cmPolicies::WARN:
         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0040) << "\n";
         issueMessage = true;
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         break;
       case cmPolicies::NEW:
@@ -1037,6 +1010,7 @@ cmTarget* cmMakefile::GetCustomCommandTarget(
       case cmPolicies::REQUIRED_ALWAYS:
         issueMessage = true;
         messageType = MessageType::FATAL_ERROR;
+        break;
     }
 
     if (issueMessage) {
@@ -1386,10 +1360,10 @@ void cmMakefile::AddLinkDirectory(std::string const& directory, bool before)
 {
   if (before) {
     this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(
-      directory, this->Backtrace);
+      BT<std::string>(directory, this->Backtrace));
   } else {
     this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(
-      directory, this->Backtrace);
+      BT<std::string>(directory, this->Backtrace));
   }
 }
 
@@ -1434,7 +1408,7 @@ bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove)
   const char* define = def.c_str() + 2;
 
   if (remove) {
-    if (cmProp cdefs = this->GetProperty("COMPILE_DEFINITIONS")) {
+    if (cmValue cdefs = this->GetProperty("COMPILE_DEFINITIONS")) {
       // Expand the list.
       std::vector<std::string> defs = cmExpandedList(*cdefs);
 
@@ -1444,7 +1418,7 @@ bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove)
       std::string ndefs = cmJoin(cmMakeRange(defBegin, defEnd), ";");
 
       // Store the new list.
-      this->SetProperty("COMPILE_DEFINITIONS", ndefs.c_str());
+      this->SetProperty("COMPILE_DEFINITIONS", ndefs);
     }
   } else {
     // Append the definition to the directory property.
@@ -1465,30 +1439,29 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent)
   // Include transform property.  There is no per-config version.
   {
     const char* prop = "IMPLICIT_DEPENDS_INCLUDE_TRANSFORM";
-    this->SetProperty(prop, cmToCStr(parent->GetProperty(prop)));
+    this->SetProperty(prop, parent->GetProperty(prop));
   }
 
   // compile definitions property and per-config versions
   cmPolicies::PolicyStatus polSt = this->GetPolicyStatus(cmPolicies::CMP0043);
   if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
     this->SetProperty("COMPILE_DEFINITIONS",
-                      cmToCStr(parent->GetProperty("COMPILE_DEFINITIONS")));
+                      parent->GetProperty("COMPILE_DEFINITIONS"));
     std::vector<std::string> configs =
       this->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
     for (std::string const& config : configs) {
       std::string defPropName =
         cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(config));
-      cmProp prop = parent->GetProperty(defPropName);
-      this->SetProperty(defPropName, cmToCStr(prop));
+      cmValue prop = parent->GetProperty(defPropName);
+      this->SetProperty(defPropName, prop);
     }
   }
 
   // labels
-  this->SetProperty("LABELS", cmToCStr(parent->GetProperty("LABELS")));
+  this->SetProperty("LABELS", parent->GetProperty("LABELS"));
 
   // link libraries
-  this->SetProperty("LINK_LIBRARIES",
-                    cmToCStr(parent->GetProperty("LINK_LIBRARIES")));
+  this->SetProperty("LINK_LIBRARIES", parent->GetProperty("LINK_LIBRARIES"));
 
   // the initial project name
   this->StateSnapshot.SetProjectName(parent->StateSnapshot.GetProjectName());
@@ -1781,6 +1754,7 @@ void cmMakefile::ConfigureSubDirectory(cmMakefile* mf)
           << cmPolicies::GetPolicyWarning(cmPolicies::CMP0014);
         /* clang-format on */
         this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         // OLD behavior does not warn.
         break;
@@ -1791,6 +1765,7 @@ void cmMakefile::ConfigureSubDirectory(cmMakefile* mf)
       case cmPolicies::NEW:
         // NEW behavior prints the error.
         this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+        break;
     }
     return;
   }
@@ -1877,16 +1852,16 @@ void cmMakefile::AddIncludeDirectories(const std::vector<std::string>& incs,
   std::string entryString = cmJoin(incs, ";");
   if (before) {
     this->StateSnapshot.GetDirectory().PrependIncludeDirectoriesEntry(
-      entryString, this->Backtrace);
+      BT<std::string>(entryString, this->Backtrace));
   } else {
     this->StateSnapshot.GetDirectory().AppendIncludeDirectoriesEntry(
-      entryString, this->Backtrace);
+      BT<std::string>(entryString, this->Backtrace));
   }
 
   // Property on each target:
   for (auto& target : this->Targets) {
     cmTarget& t = target.second;
-    t.InsertInclude(entryString, this->Backtrace, before);
+    t.InsertInclude(BT<std::string>(entryString, this->Backtrace), before);
   }
 }
 
@@ -1927,7 +1902,7 @@ void cmMakefile::AddCacheDefinition(const std::string& name, const char* value,
                                     cmStateEnums::CacheEntryType type,
                                     bool force)
 {
-  cmProp existingValue = this->GetState()->GetInitializedCacheValue(name);
+  cmValue existingValue = this->GetState()->GetInitializedCacheValue(name);
   // must be outside the following if() to keep it alive long enough
   std::string nvalue;
 
@@ -1956,7 +1931,7 @@ void cmMakefile::AddCacheDefinition(const std::string& name, const char* value,
         nvalue += files[cc];
       }
 
-      this->GetCMakeInstance()->AddCacheEntry(name, nvalue.c_str(), doc, type);
+      this->GetCMakeInstance()->AddCacheEntry(name, nvalue, doc, type);
       nvalue = *this->GetState()->GetInitializedCacheValue(name);
       value = nvalue.c_str();
     }
@@ -2045,7 +2020,7 @@ void cmMakefile::AddGlobalLinkInformation(cmTarget& target)
     default:;
   }
 
-  if (cmProp linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
+  if (cmValue linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
     std::vector<std::string> linkLibs = cmExpandedList(*linkLibsProp);
 
     for (auto j = linkLibs.begin(); j != linkLibs.end(); ++j) {
@@ -2118,15 +2093,23 @@ cmTarget* cmMakefile::AddExecutable(const std::string& exeName,
 cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type,
                                    const std::string& name)
 {
-  auto it = this->Targets
-              .emplace(name,
-                       cmTarget(name, type, cmTarget::VisibilityNormal, this,
-                                cmTarget::PerConfig::Yes))
-              .first;
+  return &this->CreateNewTarget(name, type).first;
+}
+
+std::pair<cmTarget&, bool> cmMakefile::CreateNewTarget(
+  const std::string& name, cmStateEnums::TargetType type,
+  cmTarget::PerConfig perConfig)
+{
+  auto ib = this->Targets.emplace(
+    name, cmTarget(name, type, cmTarget::VisibilityNormal, this, perConfig));
+  auto it = ib.first;
+  if (!ib.second) {
+    return std::make_pair(std::ref(it->second), false);
+  }
   this->OrderedTargets.push_back(&it->second);
   this->GetGlobalGenerator()->IndexTarget(&it->second);
   this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name);
-  return &it->second;
+  return std::make_pair(std::ref(it->second), true);
 }
 
 cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName,
@@ -2235,7 +2218,7 @@ cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(
 cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(const std::string& name)
 {
   std::string delimiters;
-  if (cmProp p = this->GetDefinition("SOURCE_GROUP_DELIMITER")) {
+  if (cmValue p = this->GetDefinition("SOURCE_GROUP_DELIMITER")) {
     delimiters = *p;
   } else {
     delimiters = "/\\";
@@ -2288,7 +2271,7 @@ void cmMakefile::ExpandVariablesCMP0019()
   }
   std::ostringstream w;
 
-  cmProp includeDirs = this->GetProperty("INCLUDE_DIRECTORIES");
+  cmValue includeDirs = this->GetProperty("INCLUDE_DIRECTORIES");
   if (includeDirs && mightExpandVariablesCMP0019(includeDirs->c_str())) {
     std::string dirs = *includeDirs;
     this->ExpandVariablesInString(dirs, true, true);
@@ -2300,7 +2283,7 @@ void cmMakefile::ExpandVariablesCMP0019()
         << "  " << dirs << "\n";
       /* clang-format on */
     }
-    this->SetProperty("INCLUDE_DIRECTORIES", dirs.c_str());
+    this->SetProperty("INCLUDE_DIRECTORIES", dirs);
   }
 
   // Also for each target's INCLUDE_DIRECTORIES property:
@@ -2326,7 +2309,7 @@ void cmMakefile::ExpandVariablesCMP0019()
     }
   }
 
-  if (cmProp linkDirsProp = this->GetProperty("LINK_DIRECTORIES")) {
+  if (cmValue linkDirsProp = this->GetProperty("LINK_DIRECTORIES")) {
     if (mightExpandVariablesCMP0019(linkDirsProp->c_str())) {
       std::string d = *linkDirsProp;
       const std::string orig = d;
@@ -2342,7 +2325,7 @@ void cmMakefile::ExpandVariablesCMP0019()
     }
   }
 
-  if (cmProp linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
+  if (cmValue linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
     std::vector<std::string> linkLibs = cmExpandedList(*linkLibsProp);
 
     for (auto l = linkLibs.begin(); l != linkLibs.end(); ++l) {
@@ -2386,7 +2369,7 @@ bool cmMakefile::IsOn(const std::string& name) const
 
 bool cmMakefile::IsSet(const std::string& name) const
 {
-  cmProp value = this->GetDefinition(name);
+  cmValue value = this->GetDefinition(name);
   if (!value) {
     return false;
   }
@@ -2404,12 +2387,12 @@ bool cmMakefile::IsSet(const std::string& name) const
 
 bool cmMakefile::PlatformIs32Bit() const
 {
-  if (cmProp plat_abi = this->GetDefinition("CMAKE_INTERNAL_PLATFORM_ABI")) {
+  if (cmValue plat_abi = this->GetDefinition("CMAKE_INTERNAL_PLATFORM_ABI")) {
     if (*plat_abi == "ELF X32") {
       return false;
     }
   }
-  if (cmProp sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) {
+  if (cmValue sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) {
     return atoi(sizeof_dptr->c_str()) == 4;
   }
   return false;
@@ -2417,7 +2400,7 @@ bool cmMakefile::PlatformIs32Bit() const
 
 bool cmMakefile::PlatformIs64Bit() const
 {
-  if (cmProp sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) {
+  if (cmValue sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) {
     return atoi(sizeof_dptr->c_str()) == 8;
   }
   return false;
@@ -2425,7 +2408,7 @@ bool cmMakefile::PlatformIs64Bit() const
 
 bool cmMakefile::PlatformIsx32() const
 {
-  if (cmProp plat_abi = this->GetDefinition("CMAKE_INTERNAL_PLATFORM_ABI")) {
+  if (cmValue plat_abi = this->GetDefinition("CMAKE_INTERNAL_PLATFORM_ABI")) {
     if (*plat_abi == "ELF X32") {
       return true;
     }
@@ -2475,7 +2458,7 @@ const char* cmMakefile::GetSONameFlag(const std::string& language) const
     name += language;
   }
   name += "_FLAG";
-  return cmToCStr(this->GetDefinition(name));
+  return this->GetDefinition(name).GetCStr();
 }
 
 bool cmMakefile::CanIWriteThisFile(std::string const& fileName) const
@@ -2498,7 +2481,7 @@ const std::string& cmMakefile::GetRequiredDefinition(
   const std::string& name) const
 {
   static std::string const empty;
-  cmProp def = this->GetDefinition(name);
+  cmValue def = this->GetDefinition(name);
   if (!def) {
     cmSystemTools::Error("Error required internal CMake variable not "
                          "set, cmake may not be built correctly.\n"
@@ -2511,7 +2494,7 @@ const std::string& cmMakefile::GetRequiredDefinition(
 
 bool cmMakefile::IsDefinitionSet(const std::string& name) const
 {
-  cmProp def = this->StateSnapshot.GetDefinition(name);
+  cmValue def = this->StateSnapshot.GetDefinition(name);
   if (!def) {
     def = this->GetState()->GetInitializedCacheValue(name);
   }
@@ -2528,7 +2511,7 @@ bool cmMakefile::IsDefinitionSet(const std::string& name) const
 
 bool cmMakefile::IsNormalDefinitionSet(const std::string& name) const
 {
-  cmProp def = this->StateSnapshot.GetDefinition(name);
+  cmValue def = this->StateSnapshot.GetDefinition(name);
 #ifndef CMAKE_BOOTSTRAP
   if (cmVariableWatch* vv = this->GetVariableWatch()) {
     if (!def) {
@@ -2540,9 +2523,9 @@ bool cmMakefile::IsNormalDefinitionSet(const std::string& name) const
   return def != nullptr;
 }
 
-cmProp cmMakefile::GetDefinition(const std::string& name) const
+cmValue cmMakefile::GetDefinition(const std::string& name) const
 {
-  cmProp def = this->StateSnapshot.GetDefinition(name);
+  cmValue def = this->StateSnapshot.GetDefinition(name);
   if (!def) {
     def = this->GetState()->GetInitializedCacheValue(name);
   }
@@ -2553,7 +2536,7 @@ cmProp cmMakefile::GetDefinition(const std::string& name) const
       vv->VariableAccessed(name,
                            def ? cmVariableWatch::VARIABLE_READ_ACCESS
                                : cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS,
-                           cmToCStr(def), this);
+                           def.GetCStr(), this);
 
     if (watch_function_executed) {
       // A callback was executed and may have caused re-allocation of the
@@ -2571,19 +2554,14 @@ cmProp cmMakefile::GetDefinition(const std::string& name) const
 
 const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const
 {
-  static std::string const empty;
-  cmProp def = this->GetDefinition(name);
-  if (!def) {
-    return empty;
-  }
-  return *def;
+  return this->GetDefinition(name);
 }
 
 bool cmMakefile::GetDefExpandList(const std::string& name,
                                   std::vector<std::string>& out,
                                   bool emptyArgs) const
 {
-  cmProp def = this->GetDefinition(name);
+  cmValue def = this->GetDefinition(name);
   if (!def) {
     return false;
   }
@@ -2736,7 +2714,7 @@ MessageType cmMakefile::ExpandVariablesInStringOld(
 
       // Lookup the definition of VAR.
       std::string var(first + 1, last - first - 2);
-      if (cmProp val = this->GetDefinition(var)) {
+      if (cmValue val = this->GetDefinition(var)) {
         // Store the value in the output escaping as requested.
         if (escapeQuotes) {
           source.append(cmEscapeQuotes(*val));
@@ -2808,6 +2786,7 @@ MessageType cmMakefile::ExpandVariablesInStringOld(
         case cmPolicies::REQUIRED_ALWAYS:
           error << "\n"
                 << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0010);
+          break;
         case cmPolicies::NEW:
           // NEW behavior is to report the error.
           break;
@@ -2941,7 +2920,7 @@ MessageType cmMakefile::ExpandVariablesInStringNew(
           openstack.pop_back();
           result.append(last, in - last);
           std::string const& lookup = result.substr(var.loc);
-          cmProp value = nullptr;
+          cmValue value = nullptr;
           std::string varresult;
           std::string svalue;
           switch (var.domain) {
@@ -2959,7 +2938,7 @@ MessageType cmMakefile::ExpandVariablesInStringNew(
               break;
             case ENVIRONMENT:
               if (cmSystemTools::GetEnv(lookup, svalue)) {
-                value = &svalue;
+                value = cmValue(svalue);
               }
               break;
             case CACHE:
@@ -3086,7 +3065,7 @@ MessageType cmMakefile::ExpandVariablesInStringNew(
             if (filename && variable == lineVar) {
               varresult = std::to_string(line);
             } else {
-              cmProp def = this->GetDefinition(variable);
+              cmValue def = this->GetDefinition(variable);
               if (def) {
                 varresult = *def;
               } else if (!this->SuppressSideEffects) {
@@ -3105,8 +3084,8 @@ MessageType cmMakefile::ExpandVariablesInStringNew(
             break;
           }
         }
-      // Failed to find a valid @ expansion; treat it as literal.
-      /* FALLTHROUGH */
+        // Failed to find a valid @ expansion; treat it as literal.
+        CM_FALLTHROUGH;
       default: {
         if (!openstack.empty() &&
             !(isalnum(inc) || inc == '_' || inc == '/' || inc == '.' ||
@@ -3182,6 +3161,23 @@ void cmMakefile::RemoveVariablesInString(std::string& source,
   }
 }
 
+void cmMakefile::InitCMAKE_CONFIGURATION_TYPES(std::string const& genDefault)
+{
+  if (this->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
+    return;
+  }
+  std::string initConfigs;
+  if (!cmSystemTools::GetEnv("CMAKE_CONFIGURATION_TYPES", initConfigs)) {
+    initConfigs = genDefault;
+  }
+  this->AddCacheDefinition(
+    "CMAKE_CONFIGURATION_TYPES", initConfigs,
+    "Semicolon separated list of supported configuration types, "
+    "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
+    "anything else will be ignored.",
+    cmStateEnums::STRING);
+}
+
 std::string cmMakefile::GetDefaultConfiguration() const
 {
   if (this->GetGlobalGenerator()->IsMultiConfig()) {
@@ -3542,8 +3538,8 @@ int cmMakefile::TryCompile(const std::string& srcdir,
   // make sure the same generator is used
   // use this program as the cmake to be run, it should not
   // be run that way but the cmake object requires a vailid path
-  cmake cm(cmake::RoleProject, cmState::Project);
-  cm.SetIsInTryCompile(true);
+  cmake cm(cmake::RoleProject, cmState::Project,
+           cmState::ProjectKind::TryCompile);
   auto gg = cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
   if (!gg) {
     this->IssueMessage(MessageType::INTERNAL_ERROR,
@@ -3565,18 +3561,19 @@ int cmMakefile::TryCompile(const std::string& srcdir,
   cm.SetGeneratorToolset(this->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET"));
   cm.LoadCache();
   if (!cm.GetGlobalGenerator()->IsMultiConfig()) {
-    if (cmProp config =
+    if (cmValue config =
           this->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION")) {
       // Tell the single-configuration generator which one to use.
       // Add this before the user-provided CMake arguments in case
       // one of the arguments is -DCMAKE_BUILD_TYPE=...
-      cm.AddCacheEntry("CMAKE_BUILD_TYPE", config->c_str(),
-                       "Build configuration", cmStateEnums::STRING);
+      cm.AddCacheEntry("CMAKE_BUILD_TYPE", config, "Build configuration",
+                       cmStateEnums::STRING);
     }
   }
-  cmProp recursionDepth = this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH");
+  cmValue recursionDepth =
+    this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH");
   if (recursionDepth) {
-    cm.AddCacheEntry("CMAKE_MAXIMUM_RECURSION_DEPTH", recursionDepth->c_str(),
+    cm.AddCacheEntry("CMAKE_MAXIMUM_RECURSION_DEPTH", recursionDepth,
                      "Maximum recursion depth", cmStateEnums::STRING);
   }
   // if cmake args were provided then pass them in
@@ -3709,7 +3706,7 @@ std::string cmMakefile::GetModulesFile(const std::string& filename,
   std::string moduleInCMakeModulePath;
 
   // Always search in CMAKE_MODULE_PATH:
-  cmProp cmakeModulePath = this->GetDefinition("CMAKE_MODULE_PATH");
+  cmValue cmakeModulePath = this->GetDefinition("CMAKE_MODULE_PATH");
   if (cmakeModulePath) {
     std::vector<std::string> modulePath = cmExpandedList(*cmakeModulePath);
 
@@ -3750,7 +3747,7 @@ std::string cmMakefile::GetModulesFile(const std::string& filename,
   }
 
   if (!moduleInCMakeModulePath.empty() && !moduleInCMakeRoot.empty()) {
-    cmProp currentFile = this->GetDefinition("CMAKE_CURRENT_LIST_FILE");
+    cmValue currentFile = this->GetDefinition("CMAKE_CURRENT_LIST_FILE");
     std::string mods = cmSystemTools::GetCMakeRoot() + "/Modules/";
     if (currentFile && cmSystemTools::IsSubDirectory(*currentFile, mods)) {
       switch (this->GetPolicyStatus(cmPolicies::CMP0017)) {
@@ -3807,7 +3804,7 @@ void cmMakefile::ConfigureString(const std::string& input, std::string& output,
 
     // Replace #cmakedefine instances.
     if (this->cmDefineRegex.find(line)) {
-      cmProp def = this->GetDefinition(this->cmDefineRegex.match(2));
+      cmValue def = this->GetDefinition(this->cmDefineRegex.match(2));
       if (!cmIsOff(def)) {
         const std::string indentation = this->cmDefineRegex.match(1);
         cmSystemTools::ReplaceString(line, "#" + indentation + "cmakedefine",
@@ -3820,7 +3817,7 @@ void cmMakefile::ConfigureString(const std::string& input, std::string& output,
       }
     } else if (this->cmDefine01Regex.find(line)) {
       const std::string indentation = this->cmDefine01Regex.match(1);
-      cmProp def = this->GetDefinition(this->cmDefine01Regex.match(2));
+      cmValue def = this->GetDefinition(this->cmDefine01Regex.match(2));
       cmSystemTools::ReplaceString(line, "#" + indentation + "cmakedefine01",
                                    "#" + indentation + "define");
       output += line;
@@ -3966,6 +3963,10 @@ void cmMakefile::SetProperty(const std::string& prop, const char* value)
 {
   this->StateSnapshot.GetDirectory().SetProperty(prop, value, this->Backtrace);
 }
+void cmMakefile::SetProperty(const std::string& prop, cmValue value)
+{
+  this->StateSnapshot.GetDirectory().SetProperty(prop, value, this->Backtrace);
+}
 
 void cmMakefile::AppendProperty(const std::string& prop,
                                 const std::string& value, bool asString)
@@ -3974,26 +3975,25 @@ void cmMakefile::AppendProperty(const std::string& prop,
                                                     this->Backtrace);
 }
 
-cmProp cmMakefile::GetProperty(const std::string& prop) const
+cmValue cmMakefile::GetProperty(const std::string& prop) const
 {
   // Check for computed properties.
   static std::string output;
   if (prop == "TESTS") {
     std::vector<std::string> keys;
     // get list of keys
-    std::transform(this->Tests.begin(), this->Tests.end(),
-                   std::back_inserter(keys),
-                   [](decltype(this->Tests)::value_type const& pair) {
-                     return pair.first;
-                   });
+    const auto* t = this;
+    std::transform(
+      t->Tests.begin(), t->Tests.end(), std::back_inserter(keys),
+      [](decltype(t->Tests)::value_type const& pair) { return pair.first; });
     output = cmJoin(keys, ";");
-    return &output;
+    return cmValue(output);
   }
 
   return this->StateSnapshot.GetDirectory().GetProperty(prop);
 }
 
-cmProp cmMakefile::GetProperty(const std::string& prop, bool chain) const
+cmValue cmMakefile::GetProperty(const std::string& prop, bool chain) const
 {
   return this->StateSnapshot.GetDirectory().GetProperty(prop, chain);
 }
@@ -4052,7 +4052,7 @@ void cmMakefile::GetTests(const std::string& config,
 void cmMakefile::AddCMakeDependFilesFromUser()
 {
   std::vector<std::string> deps;
-  if (cmProp deps_str = this->GetProperty("CMAKE_CONFIGURE_DEPENDS")) {
+  if (cmValue deps_str = this->GetProperty("CMAKE_CONFIGURE_DEPENDS")) {
     cmExpandList(*deps_str, deps);
   }
   for (std::string const& dep : deps) {
@@ -4341,7 +4341,7 @@ static std::string const nMatchesVariable = "CMAKE_MATCH_COUNT";
 
 void cmMakefile::ClearMatches()
 {
-  cmProp nMatchesStr = this->GetDefinition(nMatchesVariable);
+  cmValue nMatchesStr = this->GetDefinition(nMatchesVariable);
   if (!nMatchesStr) {
     return;
   }
@@ -4394,7 +4394,7 @@ cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus(cmPolicies::PolicyID id,
 bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var) const
 {
   // Check for an explicit CMAKE_POLICY_WARNING_CMP<NNNN> setting.
-  if (cmProp val = this->GetDefinition(var)) {
+  if (cmValue val = this->GetDefinition(var)) {
     return cmIsOn(val);
   }
   // Enable optional policy warnings with --debug-output, --trace,
@@ -4426,13 +4426,12 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
     return false;
   }
 
-  // Deprecate old policies, especially those that require a lot
-  // of code to maintain the old behavior.
-  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0081 &&
+  // Deprecate old policies.
+  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0088 &&
       !(this->GetCMakeInstance()->GetIsInTryCompile() &&
         (
           // Policies set by cmCoreTryCompile::TryCompileCode.
-          id == cmPolicies::CMP0065))) {
+          id == cmPolicies::CMP0065 || id == cmPolicies::CMP0083))) {
     this->IssueMessage(MessageType::DEPRECATION_WARNING,
                        cmPolicies::GetPolicyDeprecatedWarning(id));
   }
@@ -4511,7 +4510,8 @@ bool cmMakefile::IgnoreErrorsCMP0061() const
   bool ignoreErrors = true;
   switch (this->GetPolicyStatus(cmPolicies::CMP0061)) {
     case cmPolicies::WARN:
-    // No warning for this policy!
+      // No warning for this policy!
+      CM_FALLTHROUGH;
     case cmPolicies::OLD:
       break;
     case cmPolicies::REQUIRED_IF_USED:
index 77e9c74..671cdab 100644 (file)
@@ -13,6 +13,7 @@
 #include <stack>
 #include <string>
 #include <unordered_map>
+#include <utility>
 #include <vector>
 
 #include <cm/optional>
 #include "cmMessageType.h"
 #include "cmNewLineStyle.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmSourceFileLocationKind.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
-#include "cmStringAlgorithms.h"
+#include "cmValue.h"
 
 // IWYU does not see that 'std::unordered_map<std::string, cmTarget>'
 // will not compile without the complete type.
@@ -230,6 +230,10 @@ public:
   cmTarget* AddImportedTarget(const std::string& name,
                               cmStateEnums::TargetType type, bool global);
 
+  std::pair<cmTarget&, bool> CreateNewTarget(
+    const std::string& name, cmStateEnums::TargetType type,
+    cmTarget::PerConfig perConfig = cmTarget::PerConfig::Yes);
+
   cmTarget* AddNewTarget(cmStateEnums::TargetType type,
                          const std::string& name);
 
@@ -282,6 +286,10 @@ public:
    * can be used in CMake to refer to lists, directories, etc.
    */
   void AddDefinition(const std::string& name, cm::string_view value);
+  void AddDefinition(const std::string& name, cmValue value)
+  {
+    this->AddDefinition(name, *value);
+  }
   /**
    * Add bool variable definition to the build.
    */
@@ -310,6 +318,8 @@ public:
    */
   void SetProjectName(std::string const& name);
 
+  void InitCMAKE_CONFIGURATION_TYPES(std::string const& genDefault);
+
   /* Get the default configuration */
   std::string GetDefaultConfiguration() const;
 
@@ -392,13 +402,13 @@ public:
    * Set a regular expression that include files must match
    * in order to be considered as part of the depend information.
    */
-  void SetIncludeRegularExpression(const char* regex)
+  void SetIncludeRegularExpression(const std::string& regex)
   {
-    this->SetProperty("INCLUDE_REGULAR_EXPRESSION", regex);
+    this->SetProperty("INCLUDE_REGULAR_EXPRESSION", regex.c_str());
   }
-  const char* GetIncludeRegularExpression() const
+  const std::string& GetIncludeRegularExpression() const
   {
-    return cmToCStr(this->GetProperty("INCLUDE_REGULAR_EXPRESSION"));
+    return this->GetProperty("INCLUDE_REGULAR_EXPRESSION");
   }
 
   /**
@@ -482,7 +492,7 @@ public:
    * If the variable is not found in this makefile instance, the
    * cache is then queried.
    */
-  cmProp GetDefinition(const std::string&) const;
+  cmValue GetDefinition(const std::string&) const;
   const std::string& GetSafeDefinition(const std::string&) const;
   const std::string& GetRequiredDefinition(const std::string& name) const;
   bool IsDefinitionSet(const std::string&) const;
@@ -762,10 +772,15 @@ public:
 
   //! Set/Get a property of this directory
   void SetProperty(const std::string& prop, const char* value);
+  void SetProperty(const std::string& prop, cmValue value);
+  void SetProperty(const std::string& prop, const std::string& value)
+  {
+    this->SetProperty(prop, cmValue(value));
+  }
   void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString = false);
-  cmProp GetProperty(const std::string& prop) const;
-  cmProp GetProperty(const std::string& prop, bool chain) const;
+  cmValue GetProperty(const std::string& prop) const;
+  cmValue GetProperty(const std::string& prop, bool chain) const;
   bool GetPropertyAsBool(const std::string& prop) const;
   std::vector<std::string> GetPropertyKeys() const;
 
@@ -867,16 +882,11 @@ public:
   bool CheckCMP0037(std::string const& targetName,
                     cmStateEnums::TargetType targetType) const;
 
-  cmStringRange GetIncludeDirectoriesEntries() const;
-  cmBacktraceRange GetIncludeDirectoriesBacktraces() const;
-  cmStringRange GetCompileOptionsEntries() const;
-  cmBacktraceRange GetCompileOptionsBacktraces() const;
-  cmStringRange GetCompileDefinitionsEntries() const;
-  cmBacktraceRange GetCompileDefinitionsBacktraces() const;
-  cmStringRange GetLinkOptionsEntries() const;
-  cmBacktraceRange GetLinkOptionsBacktraces() const;
-  cmStringRange GetLinkDirectoriesEntries() const;
-  cmBacktraceRange GetLinkDirectoriesBacktraces() const;
+  cmBTStringRange GetIncludeDirectoriesEntries() const;
+  cmBTStringRange GetCompileOptionsEntries() const;
+  cmBTStringRange GetCompileDefinitionsEntries() const;
+  cmBTStringRange GetLinkOptionsEntries() const;
+  cmBTStringRange GetLinkDirectoriesEntries() const;
 
   std::set<std::string> const& GetSystemIncludeDirectories() const
   {
index e7e4a2b..575fb05 100644 (file)
@@ -21,7 +21,6 @@
 #include "cmMakefile.h"
 #include "cmOSXBundleGenerator.h"
 #include "cmOutputConverter.h"
-#include "cmProperty.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
@@ -29,6 +28,7 @@
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator(
   cmGeneratorTarget* target)
@@ -195,6 +195,8 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule(
     this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
                             buildObjs, depends, useWatcomQuote);
 
+    std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
+
     cmRulePlaceholderExpander::RuleVariables vars;
     std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
 
@@ -215,6 +217,7 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule(
                                                   cmOutputConverter::SHELL);
 
     vars.Language = linkLanguage.c_str();
+    vars.AIXExports = aixExports.c_str();
     vars.Objects = buildObjs.c_str();
     vars.ObjectDir = objectDir.c_str();
     vars.Target = target.c_str();
@@ -225,8 +228,8 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule(
 
     std::string launcher;
 
-    cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
-                                                       "RULE_LAUNCH_LINK");
+    cmValue val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
+                                                        "RULE_LAUNCH_LINK");
     if (cmNonempty(val)) {
       launcher = cmStrCat(*val, ' ');
     }
@@ -394,9 +397,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
                                     this->LocalGenerator->GetLinkLibsCMP0065(
                                       linkLanguage, *this->GeneratorTarget));
 
-  if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
-    this->LocalGenerator->AppendFlags(linkFlags, " -Wl,--no-as-needed");
-  }
+  this->UseLWYU = this->LocalGenerator->AppendLWYUFlags(
+    linkFlags, this->GeneratorTarget, linkLanguage);
 
   // Add language feature flags.
   this->LocalGenerator->AddLanguageFlagsForLinking(
@@ -525,14 +527,11 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
 
     std::string manifests = this->GetManifests(this->GetConfigName());
 
-    std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
-
     cmRulePlaceholderExpander::RuleVariables vars;
     vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
     vars.CMTargetType =
       cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
     vars.Language = linkLanguage.c_str();
-    vars.AIXExports = aixExports.c_str();
     vars.Objects = buildObjs.c_str();
     std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
 
@@ -577,18 +576,24 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
       vars.Launcher = linkerLauncher.c_str();
     }
 
-    if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
-      std::string cmakeCommand =
-        cmStrCat(this->LocalGenerator->ConvertToOutputFormat(
-                   cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
-                 " -E __run_co_compile --lwyu=", targetOutPathReal);
-      real_link_commands.push_back(std::move(cmakeCommand));
+    if (this->UseLWYU) {
+      cmValue lwyuCheck =
+        this->Makefile->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK");
+      if (lwyuCheck) {
+        std::string cmakeCommand = cmStrCat(
+          this->LocalGenerator->ConvertToOutputFormat(
+            cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
+          " -E __run_co_compile --lwyu=");
+        cmakeCommand += this->LocalGenerator->EscapeForShell(*lwyuCheck);
+        cmakeCommand += cmStrCat(" --source=", targetOutPathReal);
+        real_link_commands.push_back(std::move(cmakeCommand));
+      }
     }
 
     std::string launcher;
 
-    cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
-                                                       "RULE_LAUNCH_LINK");
+    cmValue val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
+                                                        "RULE_LAUNCH_LINK");
     if (cmNonempty(val)) {
       launcher = cmStrCat(*val, ' ');
     }
index d0e3837..ace73a7 100644 (file)
@@ -21,7 +21,6 @@
 #include "cmMakefile.h"
 #include "cmOSXBundleGenerator.h"
 #include "cmOutputConverter.h"
-#include "cmProperty.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
@@ -29,6 +28,7 @@
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator(
   cmGeneratorTarget* target)
@@ -178,9 +178,9 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
   this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags,
                                 this->GetConfigName());
 
-  if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
-    this->LocalGenerator->AppendFlags(extraFlags, " -Wl,--no-as-needed");
-  }
+  this->UseLWYU = this->LocalGenerator->AppendLWYUFlags(
+    extraFlags, this->GeneratorTarget, linkLanguage);
+
   this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
 }
 
@@ -362,8 +362,8 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules(
     vars.TargetCompilePDB = targetOutPathCompilePDB.c_str();
 
     std::string launcher;
-    cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
-                                                       "RULE_LAUNCH_LINK");
+    cmValue val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
+                                                        "RULE_LAUNCH_LINK");
     if (cmNonempty(val)) {
       launcher = cmStrCat(*val, ' ');
     }
@@ -811,8 +811,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
     }
 
     std::string launcher;
-    cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
-                                                       "RULE_LAUNCH_LINK");
+    cmValue val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
+                                                        "RULE_LAUNCH_LINK");
     if (cmNonempty(val)) {
       launcher = cmStrCat(*val, ' ');
     }
@@ -871,13 +871,18 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
       // Get the set of commands.
       std::string linkRule = this->GetLinkRule(linkRuleVar);
       cmExpandList(linkRule, real_link_commands);
-      if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE") &&
-          (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY)) {
-        std::string cmakeCommand = cmStrCat(
-          this->LocalGenerator->ConvertToOutputFormat(
-            cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
-          " -E __run_co_compile --lwyu=", targetOutPathReal);
-        real_link_commands.push_back(std::move(cmakeCommand));
+      if (this->UseLWYU) {
+        cmValue lwyuCheck =
+          this->Makefile->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK");
+        if (lwyuCheck) {
+          std::string cmakeCommand = cmStrCat(
+            this->LocalGenerator->ConvertToOutputFormat(
+              cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
+            " -E __run_co_compile --lwyu=");
+          cmakeCommand += this->LocalGenerator->EscapeForShell(*lwyuCheck);
+          cmakeCommand += cmStrCat(" --source=", targetOutPathReal);
+          real_link_commands.push_back(std::move(cmakeCommand));
+        }
       }
 
       // Expand placeholders.
index 86188db..337f78b 100644 (file)
@@ -29,7 +29,7 @@ cmMakefileProfilingData::cmMakefileProfilingData(
   }
 
   this->ProfileStream << "[";
-};
+}
 
 cmMakefileProfilingData::~cmMakefileProfilingData() noexcept
 {
index 9458277..8edadd3 100644 (file)
@@ -16,8 +16,6 @@
 #include <cmext/algorithm>
 #include <cmext/string_view>
 
-#include "cm_codecvt.hxx"
-
 #include "cmComputeLinkInformation.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
@@ -36,7 +34,6 @@
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
@@ -47,6 +44,7 @@
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target)
@@ -59,11 +57,13 @@ cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target)
     this->LocalGenerator->GetGlobalGenerator());
   cmake* cm = this->GlobalGenerator->GetCMakeInstance();
   this->NoRuleMessages = false;
-  if (cmProp ruleStatus = cm->GetState()->GetGlobalProperty("RULE_MESSAGES")) {
+  if (cmValue ruleStatus =
+        cm->GetState()->GetGlobalProperty("RULE_MESSAGES")) {
     this->NoRuleMessages = cmIsOff(*ruleStatus);
   }
   switch (this->GeneratorTarget->GetPolicyStatusCMP0113()) {
     case cmPolicies::WARN:
+      CM_FALLTHROUGH;
     case cmPolicies::OLD:
       this->CMP0113New = false;
       break;
@@ -202,14 +202,14 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
   };
 
   // Look for additional files registered for cleaning in this directory.
-  if (cmProp prop_value =
+  if (cmValue prop_value =
         this->Makefile->GetProperty("ADDITIONAL_MAKE_CLEAN_FILES")) {
     std::vector<std::string> const files = evaluatedFiles(*prop_value);
     this->CleanFiles.insert(files.begin(), files.end());
   }
 
   // Look for additional files registered for cleaning in this target.
-  if (cmProp prop_value =
+  if (cmValue prop_value =
         this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) {
     std::vector<std::string> const files = evaluatedFiles(*prop_value);
     // For relative path support
@@ -289,14 +289,13 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
   this->GeneratorTarget->GetExtraSources(extraSources, this->GetConfigName());
   this->OSXBundleGenerator->GenerateMacOSXContentStatements(
     extraSources, this->MacOSXContentGenerator.get(), this->GetConfigName());
-  cmProp pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
+  cmValue pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
   std::vector<cmSourceFile const*> externalObjects;
   this->GeneratorTarget->GetExternalObjects(externalObjects,
                                             this->GetConfigName());
   for (cmSourceFile const* sf : externalObjects) {
     auto const& objectFileName = sf->GetFullPath();
-    if (!cmSystemTools::StringEndsWith(objectFileName,
-                                       cmToCStr(pchExtension))) {
+    if (!cmHasSuffix(objectFileName, pchExtension)) {
       this->ExternalObjects.push_back(objectFileName);
     }
   }
@@ -671,12 +670,12 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
       cmSystemTools::GetFilenameWithoutLastExtension(objectName);
     ispcSource = cmSystemTools::GetFilenameWithoutLastExtension(ispcSource);
 
-    cmProp ispcSuffixProp =
+    cmValue ispcSuffixProp =
       this->GeneratorTarget->GetProperty("ISPC_HEADER_SUFFIX");
     assert(ispcSuffixProp);
 
     std::string directory = this->GeneratorTarget->GetObjectDirectory(config);
-    if (cmProp prop =
+    if (cmValue prop =
           this->GeneratorTarget->GetProperty("ISPC_HEADER_DIRECTORY")) {
       directory =
         cmStrCat(this->LocalGenerator->GetBinaryDirectory(), '/', *prop);
@@ -688,7 +687,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
 
   // Add flags from source file properties.
   const std::string COMPILE_FLAGS("COMPILE_FLAGS");
-  if (cmProp cflags = source.GetProperty(COMPILE_FLAGS)) {
+  if (cmValue cflags = source.GetProperty(COMPILE_FLAGS)) {
     const std::string& evaluatedFlags =
       genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS);
     this->LocalGenerator->AppendFlags(flags, evaluatedFlags);
@@ -698,7 +697,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
   }
 
   const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
-  if (cmProp coptions = source.GetProperty(COMPILE_OPTIONS)) {
+  if (cmValue coptions = source.GetProperty(COMPILE_OPTIONS)) {
     const std::string& evaluatedOptions =
       genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS);
     this->LocalGenerator->AppendCompileOptions(flags, evaluatedOptions);
@@ -732,7 +731,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
   std::vector<std::string> includes;
 
   const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
-  if (cmProp cincludes = source.GetProperty(INCLUDE_DIRECTORIES)) {
+  if (cmValue cincludes = source.GetProperty(INCLUDE_DIRECTORIES)) {
     const std::string& evaluatedIncludes =
       genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES);
     this->LocalGenerator->AppendIncludeDirectories(includes, evaluatedIncludes,
@@ -748,7 +747,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
 
   // Add source-specific preprocessor definitions.
   const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
-  if (cmProp compile_defs = source.GetProperty(COMPILE_DEFINITIONS)) {
+  if (cmValue compile_defs = source.GetProperty(COMPILE_DEFINITIONS)) {
     const std::string& evaluatedDefs =
       genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS);
     this->LocalGenerator->AppendDefines(defines, evaluatedDefs);
@@ -757,7 +756,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
                           << "\n";
   }
   std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", configUpper);
-  if (cmProp config_compile_defs = source.GetProperty(defPropName)) {
+  if (cmValue config_compile_defs = source.GetProperty(defPropName)) {
     const std::string& evaluatedDefs =
       genexInterpreter.Evaluate(*config_compile_defs, COMPILE_DEFINITIONS);
     this->LocalGenerator->AppendDefines(defines, evaluatedDefs);
@@ -947,11 +946,11 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
                                this->GetIncludes(lang, this->GetConfigName()));
       }
 
-      cmProp eliminate[] = {
+      cmValue eliminate[] = {
         this->Makefile->GetDefinition("CMAKE_START_TEMP_FILE"),
         this->Makefile->GetDefinition("CMAKE_END_TEMP_FILE")
       };
-      for (cmProp el : eliminate) {
+      for (cmValue el : eliminate) {
         if (el) {
           cmSystemTools::ReplaceString(compileCommand, *el, "");
         }
@@ -968,7 +967,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
          lang == "HIP" || lang == "ISPC" || lang == "OBJC" ||
          lang == "OBJCXX")) {
       std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER";
-      cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
+      cmValue clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
       if (cmNonempty(clauncher)) {
         compilerLauncher = *clauncher;
       }
@@ -978,10 +977,10 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
     if (!compileCommands.empty() &&
         (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX")) {
       std::string const tidy_prop = lang + "_CLANG_TIDY";
-      cmProp tidy = this->GeneratorTarget->GetProperty(tidy_prop);
-      cmProp iwyu = nullptr;
-      cmProp cpplint = nullptr;
-      cmProp cppcheck = nullptr;
+      cmValue tidy = this->GeneratorTarget->GetProperty(tidy_prop);
+      cmValue iwyu = nullptr;
+      cmValue cpplint = nullptr;
+      cmValue cppcheck = nullptr;
       if (lang == "C" || lang == "CXX") {
         std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE";
         iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
@@ -1002,12 +1001,30 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
         }
         if (cmNonempty(iwyu)) {
           run_iwyu += " --iwyu=";
-          run_iwyu += this->LocalGenerator->EscapeForShell(*iwyu);
+
+          // Only add --driver-mode if it is not already specified, as adding
+          // it unconditionally might override a user-specified driver-mode
+          if (iwyu.Get()->find("--driver-mode=") == std::string::npos) {
+            cmValue p = this->Makefile->GetDefinition(
+              cmStrCat("CMAKE_", lang, "_INCLUDE_WHAT_YOU_USE_DRIVER_MODE"));
+            std::string driverMode;
+
+            if (cmNonempty(p)) {
+              driverMode = *p;
+            } else {
+              driverMode = lang == "C" ? "gcc" : "g++";
+            }
+
+            run_iwyu += this->LocalGenerator->EscapeForShell(
+              cmStrCat(*iwyu, ";--driver-mode=", driverMode));
+          } else {
+            run_iwyu += this->LocalGenerator->EscapeForShell(*iwyu);
+          }
         }
         if (cmNonempty(tidy)) {
           run_iwyu += " --tidy=";
-          cmProp p = this->Makefile->GetDefinition("CMAKE_" + lang +
-                                                   "_CLANG_TIDY_DRIVER_MODE");
+          cmValue p = this->Makefile->GetDefinition("CMAKE_" + lang +
+                                                    "_CLANG_TIDY_DRIVER_MODE");
           std::string driverMode;
           if (cmNonempty(p)) {
             driverMode = *p;
@@ -1051,7 +1068,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
 
     std::string launcher;
     {
-      cmProp val = this->LocalGenerator->GetRuleLauncher(
+      cmValue val = this->LocalGenerator->GetRuleLauncher(
         this->GeneratorTarget, "RULE_LAUNCH_COMPILE");
       if (cmNonempty(val)) {
         launcher = cmStrCat(*val, ' ');
@@ -1121,7 +1138,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
 
   // Check for extra outputs created by the compilation.
   std::vector<std::string> outputs(1, relativeObj);
-  if (cmProp extra_outputs_str = source.GetProperty("OBJECT_OUTPUTS")) {
+  if (cmValue extra_outputs_str = source.GetProperty("OBJECT_OUTPUTS")) {
     std::string evaluated_outputs = cmGeneratorExpression::Evaluate(
       *extra_outputs_str, this->LocalGenerator, config);
 
@@ -1176,7 +1193,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
 
       std::string preprocessRuleVar =
         cmStrCat("CMAKE_", lang, "_CREATE_PREPROCESSED_SOURCE");
-      if (cmProp preprocessRule =
+      if (cmValue preprocessRule =
             this->Makefile->GetDefinition(preprocessRuleVar)) {
         std::vector<std::string> preprocessCommands =
           cmExpandedList(*preprocessRule);
@@ -1221,7 +1238,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
 
       std::string assemblyRuleVar =
         cmStrCat("CMAKE_", lang, "_CREATE_ASSEMBLY_SOURCE");
-      if (cmProp assemblyRule =
+      if (cmValue assemblyRule =
             this->Makefile->GetDefinition(assemblyRuleVar)) {
         std::vector<std::string> assemblyCommands =
           cmExpandedList(*assemblyRule);
@@ -1400,6 +1417,13 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
     << "set(CMAKE_Fortran_TARGET_MODULE_DIR \""
     << this->GeneratorTarget->GetFortranModuleDirectory(working_dir)
     << "\")\n";
+
+  if (this->GeneratorTarget->IsFortranBuildingInstrinsicModules()) {
+    *this->InfoFileStream
+      << "\n"
+      << "# Fortran compiler is building intrinsic modules.\n"
+      << "set(CMAKE_Fortran_TARGET_BUILDING_INSTRINSIC_MODULES ON) \n";
+  }
   /* clang-format on */
 
   // and now write the rule to use it
@@ -1485,7 +1509,7 @@ void cmMakefileTargetGenerator::WriteObjectDependRules(
   // Create the list of dependencies known at cmake time.  These are
   // shared between the object file and dependency scanning rule.
   depends.push_back(source.GetFullPath());
-  if (cmProp objectDeps = source.GetProperty("OBJECT_DEPENDS")) {
+  if (cmValue objectDeps = source.GetProperty("OBJECT_DEPENDS")) {
     cmExpandList(*objectDeps, depends);
   }
 }
@@ -1724,10 +1748,10 @@ void cmMakefileTargetGenerator::WriteObjectsVariable(
   std::string object;
   const auto& lineContinue = this->GlobalGenerator->LineContinueDirective;
 
-  cmProp pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
+  cmValue pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
 
   for (std::string const& obj : this->Objects) {
-    if (cmSystemTools::StringEndsWith(obj, cmToCStr(pchExtension))) {
+    if (cmHasSuffix(obj, pchExtension)) {
       continue;
     }
     *this->BuildFileStream << " " << lineContinue;
@@ -1811,13 +1835,13 @@ private:
 void cmMakefileTargetGenerator::WriteObjectsStrings(
   std::vector<std::string>& objStrings, std::string::size_type limit)
 {
-  cmProp pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
+  cmValue pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
 
   cmMakefileTargetGeneratorObjectStrings helper(
     objStrings, this->LocalGenerator,
     this->LocalGenerator->GetStateSnapshot().GetDirectory(), limit);
   for (std::string const& obj : this->Objects) {
-    if (cmSystemTools::StringEndsWith(obj, cmToCStr(pchExtension))) {
+    if (cmHasSuffix(obj, pchExtension)) {
       continue;
     }
     helper.Feed(obj);
@@ -1946,7 +1970,7 @@ std::string cmMakefileTargetGenerator::GetLinkRule(
       cmStrCat("CMAKE_",
                this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
                "_GNUtoMS_RULE");
-    if (cmProp rule = this->Makefile->GetDefinition(ruleVar)) {
+    if (cmValue rule = this->Makefile->GetDefinition(ruleVar)) {
       linkRule += *rule;
     }
   }
@@ -1995,7 +2019,7 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects(
   // Check for an explicit setting one way or the other.
   std::string const responseVar =
     "CMAKE_" + l + "_USE_RESPONSE_FILE_FOR_OBJECTS";
-  if (cmProp val = this->Makefile->GetDefinition(responseVar)) {
+  if (cmValue val = this->Makefile->GetDefinition(responseVar)) {
     if (!val->empty()) {
       return cmIsOn(val);
     }
@@ -2034,7 +2058,7 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForLibraries(
   // Check for an explicit setting one way or the other.
   std::string const responseVar =
     "CMAKE_" + l + "_USE_RESPONSE_FILE_FOR_LIBRARIES";
-  if (cmProp val = this->Makefile->GetDefinition(responseVar)) {
+  if (cmValue val = this->Makefile->GetDefinition(responseVar)) {
     if (!val->empty()) {
       return cmIsOn(val);
     }
@@ -2048,22 +2072,11 @@ std::string cmMakefileTargetGenerator::CreateResponseFile(
   const char* name, std::string const& options,
   std::vector<std::string>& makefile_depends)
 {
-  // FIXME: Find a better way to determine the response file encoding,
-  // perhaps using tool-specific platform information variables.
-  // For now, use the makefile encoding as a heuristic.
-  codecvt::Encoding responseEncoding =
-    this->GlobalGenerator->GetMakefileEncoding();
-  // Non-MSVC tooling may not understand a BOM.
-  if (responseEncoding == codecvt::UTF8_WITH_BOM &&
-      !this->Makefile->IsOn("MSVC")) {
-    responseEncoding = codecvt::UTF8;
-  }
-
   // Create the response file.
   std::string responseFileNameFull =
     cmStrCat(this->TargetBuildDirectoryFull, '/', name);
-  cmGeneratedFileStream responseStream(responseFileNameFull, false,
-                                       responseEncoding);
+  cmGeneratedFileStream responseStream(
+    responseFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding());
   responseStream.SetCopyIfDifferent(true);
   responseStream << options << "\n";
 
@@ -2109,7 +2122,7 @@ void cmMakefileTargetGenerator::CreateLinkLibs(
                this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
                "_RESPONSE_FILE_LINK_FLAG");
     std::string responseFlag;
-    if (cmProp p = this->Makefile->GetDefinition(responseFlagVar)) {
+    if (cmValue p = this->Makefile->GetDefinition(responseFlagVar)) {
       responseFlag = *p;
     } else {
       responseFlag = "@";
@@ -2149,7 +2162,7 @@ void cmMakefileTargetGenerator::CreateObjectLists(
                this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
                "_RESPONSE_FILE_LINK_FLAG");
     std::string responseFlag;
-    if (cmProp p = this->Makefile->GetDefinition(responseFlagVar)) {
+    if (cmValue p = this->Makefile->GetDefinition(responseFlagVar)) {
       responseFlag = *p;
     } else {
       responseFlag = "@";
@@ -2244,7 +2257,7 @@ void cmMakefileTargetGenerator::GenDefFile(
   cmd += this->LocalGenerator->ConvertToOutputFormat(
     this->LocalGenerator->MaybeRelativeToCurBinDir(objlist_file),
     cmOutputConverter::SHELL);
-  cmProp nm_executable = this->Makefile->GetDefinition("CMAKE_NM");
+  cmValue nm_executable = this->Makefile->GetDefinition("CMAKE_NM");
   if (cmNonempty(nm_executable)) {
     cmd += " --nm=";
     cmd += this->LocalCommonGenerator->ConvertToOutputFormat(
index 45043fa..73e5f33 100644 (file)
@@ -10,6 +10,7 @@
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 // cmMarkAsAdvancedCommand
index 5c21d1b..517d529 100644 (file)
@@ -32,7 +32,6 @@
 #include "cmNinjaTypes.h"
 #include "cmOSXBundleGenerator.h"
 #include "cmOutputConverter.h"
-#include "cmProperty.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
 #include "cmState.h"
@@ -41,6 +40,7 @@
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
   cmGeneratorTarget* target)
@@ -267,7 +267,7 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkRule(
     vars.LanguageCompileFlags = "$LANGUAGE_COMPILE_FLAGS";
 
     std::string launcher;
-    cmProp val = this->GetLocalGenerator()->GetRuleLauncher(
+    cmValue val = this->GetLocalGenerator()->GetRuleLauncher(
       this->GetGeneratorTarget(), "RULE_LAUNCH_LINK");
     if (cmNonempty(val)) {
       launcher = cmStrCat(*val, ' ');
@@ -390,7 +390,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
 
     // build response file name
     std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
-    cmProp flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
+    cmValue flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
 
     if (flag) {
       responseFlag = *flag;
@@ -462,7 +462,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
     }
 
     std::string launcher;
-    cmProp val = this->GetLocalGenerator()->GetRuleLauncher(
+    cmValue val = this->GetLocalGenerator()->GetRuleLauncher(
       this->GetGeneratorTarget(), "RULE_LAUNCH_LINK");
     if (cmNonempty(val)) {
       launcher = cmStrCat(*val, ' ');
@@ -569,29 +569,35 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd(
     // CMAKE_<lang>_CREATE_STATIC_LIBRARY_IPO define instead.
     std::string linkCmdVar = this->GetGeneratorTarget()->GetCreateRuleVariable(
       this->TargetLinkLanguage(config), config);
-    cmProp linkCmd = mf->GetDefinition(linkCmdVar);
+    cmValue linkCmd = mf->GetDefinition(linkCmdVar);
     if (linkCmd) {
       std::string linkCmdStr = *linkCmd;
       if (this->GetGeneratorTarget()->HasImplibGNUtoMS(config)) {
         std::string ruleVar =
           cmStrCat("CMAKE_", this->GeneratorTarget->GetLinkerLanguage(config),
                    "_GNUtoMS_RULE");
-        if (cmProp rule = this->Makefile->GetDefinition(ruleVar)) {
+        if (cmValue rule = this->Makefile->GetDefinition(ruleVar)) {
           linkCmdStr += *rule;
         }
       }
       cmExpandList(linkCmdStr, linkCmds);
-      if (this->GetGeneratorTarget()->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
-        std::string cmakeCommand = cmStrCat(
-          this->GetLocalGenerator()->ConvertToOutputFormat(
-            cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
-          " -E __run_co_compile --lwyu=");
-        cmGeneratorTarget& gt = *this->GetGeneratorTarget();
-        std::string targetOutputReal = this->ConvertToNinjaPath(
-          gt.GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact,
-                         /*realname=*/true));
-        cmakeCommand += targetOutputReal;
-        linkCmds.push_back(std::move(cmakeCommand));
+      if (this->UseLWYU) {
+        cmValue lwyuCheck = mf->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK");
+        if (lwyuCheck) {
+          std::string cmakeCommand = cmStrCat(
+            this->GetLocalGenerator()->ConvertToOutputFormat(
+              cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
+            " -E __run_co_compile --lwyu=");
+          cmakeCommand +=
+            this->GetLocalGenerator()->EscapeForShell(*lwyuCheck);
+
+          std::string targetOutputReal =
+            this->ConvertToNinjaPath(this->GetGeneratorTarget()->GetFullPath(
+              config, cmStateEnums::RuntimeBinaryArtifact,
+              /*realname=*/true));
+          cmakeCommand += cmStrCat(" --source=", targetOutputReal);
+          linkCmds.push_back(std::move(cmakeCommand));
+        }
       }
       return linkCmds;
     }
@@ -896,7 +902,7 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement(
     const std::string impLibPath = localGen.ConvertToOutputFormat(
       targetOutputImplib, cmOutputConverter::SHELL);
     vars["TARGET_IMPLIB"] = impLibPath;
-    this->EnsureParentDirectoryExists(impLibPath);
+    this->EnsureParentDirectoryExists(targetOutputImplib);
   }
 
   const std::string objPath =
@@ -1038,7 +1044,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
     }();
 
     vars["SWIFT_MODULE_NAME"] = [gt]() -> std::string {
-      if (cmProp name = gt->GetProperty("Swift_MODULE_NAME")) {
+      if (cmValue name = gt->GetProperty("Swift_MODULE_NAME")) {
         return *name;
       }
       return gt->GetName();
@@ -1047,13 +1053,13 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
     vars["SWIFT_MODULE"] = [this](const std::string& module) -> std::string {
       std::string directory =
         this->GetLocalGenerator()->GetCurrentBinaryDirectory();
-      if (cmProp prop = this->GetGeneratorTarget()->GetProperty(
+      if (cmValue prop = this->GetGeneratorTarget()->GetProperty(
             "Swift_MODULE_DIRECTORY")) {
         directory = *prop;
       }
 
       std::string name = module + ".swiftmodule";
-      if (cmProp prop =
+      if (cmValue prop =
             this->GetGeneratorTarget()->GetProperty("Swift_MODULE")) {
         name = *prop;
       }
@@ -1156,12 +1162,11 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
 
   this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"],
                                 config);
-  if (gt->GetPropertyAsBool("LINK_WHAT_YOU_USE") &&
-      (gt->GetType() == cmStateEnums::TargetType::EXECUTABLE ||
-       gt->GetType() == cmStateEnums::TargetType::SHARED_LIBRARY ||
-       gt->GetType() == cmStateEnums::TargetType::MODULE_LIBRARY)) {
-    vars["LINK_FLAGS"] += " -Wl,--no-as-needed";
-  }
+
+  this->UseLWYU = this->GetLocalGenerator()->AppendLWYUFlags(
+    vars["LINK_FLAGS"], this->GetGeneratorTarget(),
+    this->TargetLinkLanguage(config));
+
   vars["LINK_FLAGS"] = globalGen->EncodeLiteral(vars["LINK_FLAGS"]);
 
   vars["MANIFESTS"] = this->GetManifests(config);
@@ -1206,7 +1211,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
     const std::string impLibPath = localGen.ConvertToOutputFormat(
       targetOutputImplib, cmOutputConverter::SHELL);
     vars["TARGET_IMPLIB"] = impLibPath;
-    this->EnsureParentDirectoryExists(impLibPath);
+    this->EnsureParentDirectoryExists(targetOutputImplib);
     if (gt->HasImportLibrary(config)) {
       // Some linkers may update a binary without touching its import lib.
       byproducts.ExplicitOuts.emplace_back(targetOutputImplib);
@@ -1226,7 +1231,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
     gt->GetFullNameComponents(prefix, base, suffix, config);
     std::string dbg_suffix = ".dbg";
     // TODO: Where to document?
-    if (cmProp d = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) {
+    if (cmValue d = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) {
       dbg_suffix = *d;
     }
     vars["TARGET_PDB"] = base + suffix + dbg_suffix;
@@ -1292,7 +1297,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
     cmd += this->GetLocalGenerator()->ConvertToOutputFormat(
       obj_list_file, cmOutputConverter::SHELL);
 
-    cmProp nm_executable = this->GetMakefile()->GetDefinition("CMAKE_NM");
+    cmValue nm_executable = this->GetMakefile()->GetDefinition("CMAKE_NM");
     if (cmNonempty(nm_executable)) {
       cmd += " --nm=";
       cmd += this->LocalCommonGenerator->ConvertToOutputFormat(
@@ -1346,7 +1351,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
   // build response file name
   std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
 
-  cmProp flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
+  cmValue flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
 
   bool const lang_supports_response =
     !(this->TargetLinkLanguage(config) == "RC" ||
index 609848b..57657b1 100644 (file)
@@ -31,7 +31,6 @@
 #include "cmNinjaNormalTargetGenerator.h"
 #include "cmNinjaUtilityTargetGenerator.h"
 #include "cmOutputConverter.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
@@ -40,6 +39,7 @@
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 std::unique_ptr<cmNinjaTargetGenerator> cmNinjaTargetGenerator::New(
@@ -224,13 +224,13 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
     this->LocalGenerator, config, this->GeneratorTarget, language);
 
   const std::string COMPILE_FLAGS("COMPILE_FLAGS");
-  if (cmProp cflags = source->GetProperty(COMPILE_FLAGS)) {
+  if (cmValue cflags = source->GetProperty(COMPILE_FLAGS)) {
     this->LocalGenerator->AppendFlags(
       flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
   }
 
   const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
-  if (cmProp coptions = source->GetProperty(COMPILE_OPTIONS)) {
+  if (cmValue coptions = source->GetProperty(COMPILE_OPTIONS)) {
     this->LocalGenerator->AppendCompileOptions(
       flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
   }
@@ -290,14 +290,14 @@ std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source,
   }
 
   const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
-  if (cmProp compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) {
+  if (cmValue compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) {
     this->LocalGenerator->AppendDefines(
       defines, genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS));
   }
 
   std::string defPropName =
     cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(config));
-  if (cmProp config_compile_defs = source->GetProperty(defPropName)) {
+  if (cmValue config_compile_defs = source->GetProperty(defPropName)) {
     this->LocalGenerator->AppendDefines(
       defines,
       genexInterpreter.Evaluate(*config_compile_defs, COMPILE_DEFINITIONS));
@@ -318,7 +318,7 @@ std::string cmNinjaTargetGenerator::ComputeIncludes(
     this->LocalGenerator, config, this->GeneratorTarget, language);
 
   const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
-  if (cmProp cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) {
+  if (cmValue cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) {
     this->LocalGenerator->AppendIncludeDirectories(
       includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES),
       *source);
@@ -638,7 +638,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
     cmLocalGenerator::SHELL);
 
   std::string launcher;
-  cmProp val = this->GetLocalGenerator()->GetRuleLauncher(
+  cmValue val = this->GetLocalGenerator()->GetRuleLauncher(
     this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE");
   if (cmNonempty(val)) {
     launcher = cmStrCat(*val, ' ');
@@ -771,11 +771,14 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
     if (!mf->GetIsSourceFileTryCompile()) {
       rule.DepType = "gcc";
       rule.DepFile = "$DEP_FILE";
-      cmProp d = mf->GetDefinition("CMAKE_C_COMPILER");
+      cmValue d = mf->GetDefinition("CMAKE_C_COMPILER");
       const std::string cl =
         d ? *d : mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
-      cldeps = cmStrCat('"', cmSystemTools::GetCMClDepsCommand(), "\" ", lang,
-                        ' ', vars.Source, " $DEP_FILE $out \"",
+      std::string cmcldepsPath;
+      cmSystemTools::GetShortPath(cmSystemTools::GetCMClDepsCommand(),
+                                  cmcldepsPath);
+      cldeps = cmStrCat(cmcldepsPath, ' ', lang, ' ', vars.Source,
+                        " $DEP_FILE $out \"",
                         mf->GetSafeDefinition("CMAKE_CL_SHOWINCLUDES_PREFIX"),
                         "\" \"", cl, "\" ");
     }
@@ -840,7 +843,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
        lang == "HIP" || lang == "ISPC" || lang == "OBJC" ||
        lang == "OBJCXX")) {
     std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER");
-    cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
+    cmValue clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
     if (cmNonempty(clauncher)) {
       compilerLauncher = *clauncher;
     }
@@ -850,10 +853,10 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
   if (!compileCmds.empty() &&
       (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX")) {
     std::string const tidy_prop = cmStrCat(lang, "_CLANG_TIDY");
-    cmProp tidy = this->GeneratorTarget->GetProperty(tidy_prop);
-    cmProp iwyu = nullptr;
-    cmProp cpplint = nullptr;
-    cmProp cppcheck = nullptr;
+    cmValue tidy = this->GeneratorTarget->GetProperty(tidy_prop);
+    cmValue iwyu = nullptr;
+    cmValue cpplint = nullptr;
+    cmValue cppcheck = nullptr;
     if (lang == "C" || lang == "CXX") {
       std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE");
       iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
@@ -874,12 +877,30 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
         compilerLauncher.clear();
       }
       if (cmNonempty(iwyu)) {
-        run_iwyu += cmStrCat(" --iwyu=",
-                             this->GetLocalGenerator()->EscapeForShell(*iwyu));
+        run_iwyu += " --iwyu=";
+
+        // Only add --driver-mode if it is not already specified, as adding
+        // it unconditionally might override a user-specified driver-mode
+        if (iwyu.Get()->find("--driver-mode=") == std::string::npos) {
+          cmValue p = this->Makefile->GetDefinition(
+            cmStrCat("CMAKE_", lang, "_INCLUDE_WHAT_YOU_USE_DRIVER_MODE"));
+          std::string driverMode;
+
+          if (cmNonempty(p)) {
+            driverMode = *p;
+          } else {
+            driverMode = lang == "C" ? "gcc" : "g++";
+          }
+
+          run_iwyu += this->LocalGenerator->EscapeForShell(
+            cmStrCat(*iwyu, ";--driver-mode=", driverMode));
+        } else {
+          run_iwyu += this->LocalGenerator->EscapeForShell(*iwyu);
+        }
       }
       if (cmNonempty(tidy)) {
         run_iwyu += " --tidy=";
-        cmProp p = this->Makefile->GetDefinition(
+        cmValue p = this->Makefile->GetDefinition(
           cmStrCat("CMAKE_", lang, "_CLANG_TIDY_DRIVER_MODE"));
         std::string driverMode;
         if (cmNonempty(p)) {
@@ -986,7 +1007,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
       config);
   }
   if (firstForConfig) {
-    cmProp pchExtension =
+    cmValue pchExtension =
       this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION");
 
     std::vector<cmSourceFile const*> externalObjects;
@@ -994,8 +1015,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
     for (cmSourceFile const* sf : externalObjects) {
       auto objectFileName = this->GetGlobalGenerator()->ExpandCFGIntDir(
         this->ConvertToNinjaPath(sf->GetFullPath()), config);
-      if (!cmSystemTools::StringEndsWith(objectFileName,
-                                         cmToCStr(pchExtension))) {
+      if (!cmHasSuffix(objectFileName, pchExtension)) {
         this->Configs[config].Objects.push_back(objectFileName);
       }
     }
@@ -1092,7 +1112,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
                "output-file-map.json");
     std::string const targetSwiftDepsPath = [this, config]() -> std::string {
       cmGeneratorTarget const* target = this->GeneratorTarget;
-      if (cmProp name = target->GetProperty("Swift_DEPENDENCIES_FILE")) {
+      if (cmValue name = target->GetProperty("Swift_DEPENDENCIES_FILE")) {
         return *name;
       }
       return this->ConvertToNinjaPath(
@@ -1216,7 +1236,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
   // build response file name
   std::string cmakeLinkVar = cmStrCat(cmakeVarLang, "_RESPONSE_FILE_FLAG");
 
-  cmProp flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
+  cmValue flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
 
   bool const lang_supports_response =
     !(language == "RC" || (language == "CUDA" && !flag));
@@ -1258,10 +1278,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
 
   objBuild.Outputs.push_back(objectFileName);
   if (firstForConfig) {
-    cmProp pchExtension =
+    cmValue pchExtension =
       this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION");
-    if (!cmSystemTools::StringEndsWith(objectFileName,
-                                       cmToCStr(pchExtension))) {
+    if (!cmHasSuffix(objectFileName, pchExtension)) {
       // Add this object to the list of object files.
       this->Configs[config].Objects.push_back(objectFileName);
     }
@@ -1299,7 +1318,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
     }
   }
 
-  if (cmProp objectDeps = source->GetProperty("OBJECT_DEPENDS")) {
+  if (cmValue objectDeps = source->GetProperty("OBJECT_DEPENDS")) {
     std::vector<std::string> objDepList = cmExpandedList(*objectDeps);
     std::copy(objDepList.begin(), objDepList.end(),
               std::back_inserter(depList));
@@ -1445,13 +1464,13 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
       cmSystemTools::GetFilenameWithoutLastExtension(objectName);
     ispcSource = cmSystemTools::GetFilenameWithoutLastExtension(ispcSource);
 
-    cmProp ispcSuffixProp =
+    cmValue ispcSuffixProp =
       this->GeneratorTarget->GetProperty("ISPC_HEADER_SUFFIX");
     assert(ispcSuffixProp);
 
     std::string ispcHeaderDirectory =
       this->GeneratorTarget->GetObjectDirectory(config);
-    if (cmProp prop =
+    if (cmValue prop =
           this->GeneratorTarget->GetProperty("ISPC_HEADER_DIRECTORY")) {
       ispcHeaderDirectory =
         cmStrCat(this->LocalGenerator->GetBinaryDirectory(), '/', *prop);
@@ -1502,7 +1521,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
                                            objBuild, commandLineLengthLimit);
   }
 
-  if (cmProp objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) {
+  if (cmValue objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) {
     std::string evaluatedObjectOutputs = cmGeneratorExpression::Evaluate(
       *objectOutputs, this->LocalGenerator, config);
 
@@ -1582,13 +1601,13 @@ void cmNinjaTargetGenerator::EmitSwiftDependencyInfo(
   std::string const objectFilePath =
     this->ConvertToNinjaPath(this->GetObjectFilePath(source, config));
   std::string const swiftDepsPath = [source, objectFilePath]() -> std::string {
-    if (cmProp name = source->GetProperty("Swift_DEPENDENCIES_FILE")) {
+    if (cmValue name = source->GetProperty("Swift_DEPENDENCIES_FILE")) {
       return *name;
     }
     return cmStrCat(objectFilePath, ".swiftdeps");
   }();
   std::string const swiftDiaPath = [source, objectFilePath]() -> std::string {
-    if (cmProp name = source->GetProperty("Swift_DIAGNOSTICS_FILE")) {
+    if (cmValue name = source->GetProperty("Swift_DIAGNOSTICS_FILE")) {
       return *name;
     }
     return cmStrCat(objectFilePath, ".dia");
@@ -1696,7 +1715,7 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand(
 
 void cmNinjaTargetGenerator::AdditionalCleanFiles(const std::string& config)
 {
-  if (cmProp prop_value =
+  if (cmValue prop_value =
         this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) {
     cmLocalNinjaGenerator* lg = this->LocalGenerator;
     std::vector<std::string> cleanFiles;
@@ -1730,7 +1749,7 @@ void cmNinjaTargetGenerator::EnsureDirectoryExists(
   } else {
     cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
     std::string fullPath = gg->GetCMakeInstance()->GetHomeOutputDirectory();
-    // Also ensures their is a trailing slash.
+    // Also ensures there is a trailing slash.
     gg->StripNinjaOutputPathPrefixAsSuffix(fullPath);
     fullPath += path;
     cmSystemTools::MakeDirectory(fullPath);
@@ -1786,7 +1805,7 @@ void cmNinjaTargetGenerator::addPoolNinjaVariable(
   const std::string& pool_property, cmGeneratorTarget* target,
   cmNinjaVars& vars)
 {
-  cmProp pool = target->GetProperty(pool_property);
+  cmValue pool = target->GetProperty(pool_property);
   if (pool) {
     vars["pool"] = *pool;
   }
index 1f5a7ff..15197ba 100644 (file)
 #include "cmLocalNinjaGenerator.h"
 #include "cmNinjaTypes.h"
 #include "cmOutputConverter.h"
-#include "cmProperty.h"
 #include "cmSourceFile.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 
 cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator(
   cmGeneratorTarget* target)
@@ -141,7 +141,7 @@ void cmNinjaUtilityTargetGenerator::WriteUtilBuildStatements(
     std::string command = lg->BuildCommandLine(
       commands, config, fileConfig, "utility", this->GeneratorTarget);
     std::string desc;
-    cmProp echoStr = genTarget->GetProperty("EchoString");
+    cmValue echoStr = genTarget->GetProperty("EchoString");
     if (echoStr) {
       desc = *echoStr;
     } else {
index bae67e0..ec54fc5 100644 (file)
@@ -6,11 +6,11 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
+#include "cmValue.h"
 
 // cmOptionCommand
 bool cmOptionCommand(std::vector<std::string> const& args,
@@ -29,12 +29,12 @@ bool cmOptionCommand(std::vector<std::string> const& args,
   {
     auto policyStatus =
       status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0077);
-    const auto* existsBeforeSet =
+    const auto& existsBeforeSet =
       status.GetMakefile().GetStateSnapshot().GetDefinition(args[0]);
     switch (policyStatus) {
       case cmPolicies::WARN:
         checkAndWarn = (existsBeforeSet != nullptr);
-        break;
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         // OLD behavior does not warn.
         break;
@@ -53,7 +53,7 @@ bool cmOptionCommand(std::vector<std::string> const& args,
   // See if a cache variable with this name already exists
   // If so just make sure the doc state is correct
   cmState* state = status.GetMakefile().GetState();
-  cmProp existingValue = state->GetCacheEntryValue(args[0]);
+  cmValue existingValue = state->GetCacheEntryValue(args[0]);
   if (existingValue &&
       (state->GetCacheEntryType(args[0]) != cmStateEnums::UNINITIALIZED)) {
     state->SetCacheEntryProperty(args[0], "HELPSTRING", args[1]);
@@ -77,7 +77,7 @@ bool cmOptionCommand(std::vector<std::string> const& args,
   }
 
   if (checkAndWarn) {
-    const auto* existsAfterSet =
+    const auto& existsAfterSet =
       status.GetMakefile().GetStateSnapshot().GetDefinition(args[0]);
     if (!existsAfterSet) {
       status.GetMakefile().IssueMessage(
index 840fdb9..2b785e1 100644 (file)
 #include "cmStateDirectory.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 namespace {
 bool PathEqOrSubDir(std::string const& a, std::string const& b)
 {
   return (cmSystemTools::ComparePath(a, b) ||
           cmSystemTools::IsSubDirectory(a, b));
-};
+}
 }
 
 cmOutputConverter::cmOutputConverter(cmStateSnapshot const& snapshot)
index d589614..ad276d2 100644 (file)
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmSourceFile.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 
 namespace {
 /** \class cmDependInformation
@@ -118,7 +118,7 @@ public:
     std::set<std::string> uniqueIncludes;
     std::vector<std::string> orderedAndUniqueIncludes;
     for (auto const& target : this->Makefile->GetTargets()) {
-      cmProp incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES");
+      cmValue incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES");
       if (!incDirProp) {
         continue;
       }
index 2465069..9f3fd00 100644 (file)
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 static std::string EscapeArg(const std::string& arg)
 {
@@ -196,7 +196,7 @@ bool cmParseArgumentsCommand(std::vector<std::string> const& args,
     for (unsigned long i = argvStart; i < count; ++i) {
       std::ostringstream argName;
       argName << "ARGV" << i;
-      cmProp arg = status.GetMakefile().GetDefinition(argName.str());
+      cmValue arg = status.GetMakefile().GetDefinition(argName.str());
       if (!arg) {
         status.GetMakefile().IssueMessage(MessageType::FATAL_ERROR,
                                           "PARSE_ARGV called with " +
index 01e8c04..23000fa 100644 (file)
@@ -15,6 +15,7 @@
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 
 static bool stringToId(const char* input, cmPolicies::PolicyID& pid)
index f7c0d25..ce04117 100644 (file)
@@ -379,7 +379,13 @@ class cmMakefile;
          3, 21, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0126,                                                     \
          "set(CACHE) does not remove a normal variable of the same name.", 3, \
-         21, 0, cmPolicies::WARN)
+         21, 0, cmPolicies::WARN)                                             \
+  SELECT(POLICY, CMP0127,                                                     \
+         "cmake_dependent_option() supports full Condition Syntax.", 3, 22,   \
+         0, cmPolicies::WARN)                                                 \
+  SELECT(POLICY, CMP0128,                                                     \
+         "Selection of language standard and extension flags improved.", 3,   \
+         22, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
index 6950c19..20fcdbe 100644 (file)
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 static bool IncludeByVariable(cmExecutionStatus& status,
                               const std::string& variable);
@@ -308,7 +308,7 @@ bool cmProjectCommand(std::vector<std::string> const& args,
     }
     std::string vw;
     for (std::string const& i : vv) {
-      cmProp v = mf.GetDefinition(i);
+      cmValue v = mf.GetDefinition(i);
       if (cmNonempty(v)) {
         if (cmp0048 == cmPolicies::WARN) {
           if (!injectedProjectCommand) {
@@ -358,7 +358,7 @@ static bool IncludeByVariable(cmExecutionStatus& status,
                               const std::string& variable)
 {
   cmMakefile& mf = status.GetMakefile();
-  cmProp include = mf.GetDefinition(variable);
+  cmValue include = mf.GetDefinition(variable);
   if (!include) {
     return true;
   }
index 1e03c3f..0781109 100644 (file)
@@ -4,8 +4,6 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
-#include <string>
-
 class cmProperty
 {
 public:
@@ -22,15 +20,3 @@ public:
     INSTALL
   };
 };
-
-using cmProp = const std::string*;
-
-inline const char* cmToCStr(cmProp p)
-{
-  return p ? p->c_str() : nullptr;
-}
-
-inline const char* cmToCStrSafe(cmProp p)
-{
-  return p ? p->c_str() : "";
-}
index 06e151a..b15000f 100644 (file)
@@ -19,6 +19,15 @@ void cmPropertyMap::SetProperty(const std::string& name, const char* value)
 
   this->Map_[name] = value;
 }
+void cmPropertyMap::SetProperty(const std::string& name, cmValue value)
+{
+  if (!value) {
+    this->Map_.erase(name);
+    return;
+  }
+
+  this->Map_[name] = *value;
+}
 
 void cmPropertyMap::AppendProperty(const std::string& name,
                                    const std::string& value, bool asString)
@@ -42,11 +51,11 @@ void cmPropertyMap::RemoveProperty(const std::string& name)
   this->Map_.erase(name);
 }
 
-cmProp cmPropertyMap::GetPropertyValue(const std::string& name) const
+cmValue cmPropertyMap::GetPropertyValue(const std::string& name) const
 {
   auto it = this->Map_.find(name);
   if (it != this->Map_.end()) {
-    return &it->second;
+    return cmValue(it->second);
   }
   return nullptr;
 }
index cda585a..f50b65e 100644 (file)
@@ -9,7 +9,7 @@
 #include <utility>
 #include <vector>
 
-#include "cmProperty.h"
+#include "cmValue.h"
 
 /** \class cmPropertyMap
  * \brief String property map.
@@ -26,13 +26,18 @@ public:
 
   //! Set the property value
   void SetProperty(const std::string& name, const char* value);
+  void SetProperty(const std::string& name, cmValue value);
+  void SetProperty(const std::string& name, const std::string& value)
+  {
+    this->SetProperty(name, cmValue(value));
+  }
 
   //! Append to the property value
   void AppendProperty(const std::string& name, const std::string& value,
                       bool asString = false);
 
   //! Get the property value
-  cmProp GetPropertyValue(const std::string& name) const;
+  cmValue GetPropertyValue(const std::string& name) const;
 
   //! Remove the property @a name from the map
   void RemoveProperty(const std::string& name);
index e9670f9..ca0b259 100644 (file)
@@ -6,7 +6,6 @@
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmStringAlgorithms.h"
@@ -41,7 +40,7 @@ bool cmQTWrapCPPCommand(std::vector<std::string> const& args,
         cmStrCat(mf.GetCurrentBinaryDirectory(), "/moc_", srcName, ".cxx");
       cmSourceFile* sf = mf.GetOrCreateSource(newName, true);
       if (curr) {
-        sf->SetProperty("ABSTRACT", cmToCStr(curr->GetProperty("ABSTRACT")));
+        sf->SetProperty("ABSTRACT", curr->GetProperty("ABSTRACT"));
       }
 
       // Compute the name of the header from which to generate the file.
index 57fcd2d..9584e5c 100644 (file)
@@ -24,7 +24,8 @@
 /// @arg valueOpts list of options that accept a value
 void MergeOptions(std::vector<std::string>& baseOpts,
                   std::vector<std::string> const& newOpts,
-                  std::initializer_list<cm::string_view> valueOpts, bool isQt5)
+                  std::initializer_list<cm::string_view> valueOpts,
+                  bool isQt5OrLater)
 {
   if (newOpts.empty()) {
     return;
@@ -47,7 +48,7 @@ void MergeOptions(std::vector<std::string>& baseOpts,
           auto oit = newOpt.begin();
           if (*oit == '-') {
             ++oit;
-            if (isQt5 && (*oit == '-')) {
+            if (isQt5OrLater && (*oit == '-')) {
               ++oit;
             }
             optName.assign(oit, newOpt.end());
@@ -204,24 +205,24 @@ std::string cmQtAutoGen::AppendFilenameSuffix(cm::string_view filename,
 
 void cmQtAutoGen::UicMergeOptions(std::vector<std::string>& baseOpts,
                                   std::vector<std::string> const& newOpts,
-                                  bool isQt5)
+                                  bool isQt5OrLater)
 {
   static std::initializer_list<cm::string_view> const valueOpts = {
     "tr",      "translate", "postfix", "generator",
     "include", // Since Qt 5.3
     "g"
   };
-  MergeOptions(baseOpts, newOpts, valueOpts, isQt5);
+  MergeOptions(baseOpts, newOpts, valueOpts, isQt5OrLater);
 }
 
 void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts,
                                   std::vector<std::string> const& newOpts,
-                                  bool isQt5)
+                                  bool isQt5OrLater)
 {
   static std::initializer_list<cm::string_view> const valueOpts = {
     "name", "root", "compress", "threshold"
   };
-  MergeOptions(baseOpts, newOpts, valueOpts, isQt5);
+  MergeOptions(baseOpts, newOpts, valueOpts, isQt5OrLater);
 }
 
 static void RccListParseContent(std::string const& content,
index 466a954..5a23ae9 100644 (file)
@@ -93,12 +93,12 @@ public:
   /// @brief Merges newOpts into baseOpts
   static void UicMergeOptions(std::vector<std::string>& baseOpts,
                               std::vector<std::string> const& newOpts,
-                              bool isQt5);
+                              bool isQt5OrLater);
 
   /// @brief Merges newOpts into baseOpts
   static void RccMergeOptions(std::vector<std::string>& baseOpts,
                               std::vector<std::string> const& newOpts,
-                              bool isQt5);
+                              bool isQt5OrLater);
 
   /** @class RccLister
    * @brief Lists files in qrc resource files
index 77fe87e..f9e889a 100644 (file)
@@ -15,7 +15,6 @@
 #include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmProcessOutput.h"
-#include "cmProperty.h"
 #include "cmQtAutoGen.h"
 #include "cmQtAutoGenInitializer.h"
 #include "cmState.h"
@@ -23,6 +22,7 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 
 cmQtAutoGenGlobalInitializer::Keywords::Keywords()
   : AUTOMOC("AUTOMOC")
@@ -183,10 +183,10 @@ void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget(
 
     // Set FOLDER property in the target
     {
-      cmProp folder =
+      cmValue folder =
         makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER");
       if (folder) {
-        target->SetProperty("FOLDER", *folder);
+        target->SetProperty("FOLDER", folder);
       }
     }
   }
index afcb4a2..3de5c1a 100644 (file)
@@ -49,7 +49,7 @@ public:
     std::vector<std::unique_ptr<cmLocalGenerator>> const& localGenerators);
   ~cmQtAutoGenGlobalInitializer();
 
-  Keywords const& kw() const { return this->Keywords_; };
+  Keywords const& kw() const { return this->Keywords_; }
 
   bool generate();
 
index 4e3c584..c49cafe 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "cmsys/SystemInformation.hxx"
 
+#include "cmAlgorithms.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
 #include "cmGeneratedFileStream.h"
@@ -36,7 +37,6 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmQtAutoGen.h"
 #include "cmQtAutoGenGlobalInitializer.h"
 #include "cmSourceFile.h"
@@ -47,6 +47,7 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 namespace {
@@ -355,7 +356,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
 
   // Targets FOLDER
   {
-    cmProp folder =
+    cmValue folder =
       this->Makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER");
     if (!folder) {
       folder = this->Makefile->GetState()->GetGlobalProperty(
@@ -522,6 +523,8 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
       // Filters
       cmExpandList(this->GenTarget->GetSafeProperty("AUTOMOC_MACRO_NAMES"),
                    this->Moc.MacroNames);
+      this->Moc.MacroNames.erase(cmRemoveDuplicates(this->Moc.MacroNames),
+                                 this->Moc.MacroNames.end());
       {
         auto filterList = cmExpandedList(
           this->GenTarget->GetSafeProperty("AUTOMOC_DEPEND_FILTERS"));
@@ -1796,7 +1799,7 @@ void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
         cmStrCat(genNameUpper, "_SOURCE_GROUP"), "AUTOGEN_SOURCE_GROUP"
       };
       for (std::string const& prop : props) {
-        cmProp propName = this->Makefile->GetState()->GetGlobalProperty(prop);
+        cmValue propName = this->Makefile->GetState()->GetGlobalProperty(prop);
         if (cmNonempty(propName)) {
           groupName = *propName;
           property = prop;
@@ -1926,7 +1929,7 @@ cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target,
     }
     return 0u;
   };
-  auto toUInt2 = [](cmProp input) -> unsigned int {
+  auto toUInt2 = [](cmValue input) -> unsigned int {
     unsigned long tmp = 0;
     if (input && cmStrToULong(*input, &tmp)) {
       return static_cast<unsigned int>(tmp);
@@ -1954,8 +1957,8 @@ cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target,
     knownQtVersions.reserve(keys.size() * 2);
 
     // Adds a version to the result (nullptr safe)
-    auto addVersion = [&knownQtVersions, &toUInt2](cmProp major,
-                                                   cmProp minor) {
+    auto addVersion = [&knownQtVersions, &toUInt2](cmValue major,
+                                                   cmValue minor) {
       cmQtAutoGen::IntegerVersion ver(toUInt2(major), toUInt2(minor));
       if (ver.Major != 0) {
         knownQtVersions.emplace_back(ver);
index e76817b..603c537 100644 (file)
@@ -95,7 +95,9 @@ public:
 
     GenVarsT(GenT gen)
       : Gen(gen)
-      , GenNameUpper(cmQtAutoGen::GeneratorNameUpper(gen)){};
+      , GenNameUpper(cmQtAutoGen::GeneratorNameUpper(gen))
+    {
+    }
   };
 
   /** @param mocExecutable The file path to the moc executable. Will be used as
@@ -209,7 +211,9 @@ private:
   struct MocT : public GenVarsT
   {
     MocT()
-      : GenVarsT(GenT::MOC){};
+      : GenVarsT(GenT::MOC)
+    {
+    }
 
     bool RelaxedMode = false;
     bool PathPrefix = false;
@@ -237,7 +241,9 @@ private:
     using UiFileT = std::pair<std::string, std::vector<std::string>>;
 
     UicT()
-      : GenVarsT(GenT::UIC){};
+      : GenVarsT(GenT::UIC)
+    {
+    }
 
     std::set<std::string> SkipUi;
     std::vector<std::string> UiFilesNoOptions;
@@ -252,7 +258,9 @@ private:
   struct RccT : public GenVarsT
   {
     RccT()
-      : GenVarsT(GenT::RCC){};
+      : GenVarsT(GenT::RCC)
+    {
+    }
 
     bool GlobalTarget = false;
     std::vector<Qrc> Qrcs;
index 568926e..e5c7bda 100644 (file)
@@ -9,6 +9,7 @@
 #include "cmQtAutoGen.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmQtAutoGenerator::Logger::Logger()
 {
index 2753fd5..4ed728e 100644 (file)
@@ -310,7 +310,7 @@ public:
     cmQtAutoMocUicT* Gen() const
     {
       return static_cast<cmQtAutoMocUicT*>(this->UserData());
-    };
+    }
 
     // -- Accessors. Only valid during Process() call!
     Logger const& Log() const { return this->Gen()->Log(); }
@@ -346,7 +346,7 @@ public:
       : JobT(true)
     {
     }
-    void Process() override{};
+    void Process() override {}
   };
 
   /** Generate moc_predefs.h.  */
@@ -2083,7 +2083,7 @@ void cmQtAutoMocUicT::JobCompileUicT::Process()
     auto optionIt = this->UicConst().UiFiles.find(sourceFile);
     if (optionIt != this->UicConst().UiFiles.end()) {
       UicMergeOptions(allOpts, optionIt->second.Options,
-                      (this->BaseConst().QtVersion.Major == 5));
+                      (this->BaseConst().QtVersion.Major >= 5));
     }
     cm::append(cmd, allOpts);
   }
index fce6e80..1e4dedd 100644 (file)
@@ -35,6 +35,7 @@ cmRST::cmRST(std::ostream& os, std::string docroot)
   , TocTreeDirective("^.. toctree::[ \t]*(.*)$")
   , ProductionListDirective("^.. productionlist::[ \t]*(.*)$")
   , NoteDirective("^.. note::[ \t]*(.*)$")
+  , VersionDirective("^.. version(added|changed)::[ \t]*(.*)$")
   , ModuleRST(R"(^#\[(=*)\[\.rst:$)")
   , CMakeRole("(:cmake)?:("
               "command|cpack_gen|generator|genex|"
@@ -209,6 +210,10 @@ void cmRST::ProcessLine(std::string const& line)
     } else if (this->NoteDirective.find(line)) {
       // Output note directives and their content normally.
       this->NormalLine(line);
+    } else if (this->VersionDirective.find(line)) {
+      // Output versionadded and versionchanged directives and their content
+      // normally.
+      this->NormalLine(line);
     }
   }
   // An explicit markup start followed nothing but whitespace and a
index 17cdfe8..156b20a 100644 (file)
@@ -83,6 +83,7 @@ private:
   cmsys::RegularExpression TocTreeDirective;
   cmsys::RegularExpression ProductionListDirective;
   cmsys::RegularExpression NoteDirective;
+  cmsys::RegularExpression VersionDirective;
   cmsys::RegularExpression ModuleRST;
   cmsys::RegularExpression CMakeRole;
   cmsys::RegularExpression InlineLink;
index 1345588..8af13ae 100644 (file)
@@ -4,8 +4,8 @@
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
+#include "cmValue.h"
 
 // cmRemoveCommand
 bool cmRemoveCommand(std::vector<std::string> const& args,
@@ -17,7 +17,7 @@ bool cmRemoveCommand(std::vector<std::string> const& args,
 
   std::string const& variable = args[0]; // VAR is always first
   // get the old value
-  cmProp cacheValue = status.GetMakefile().GetDefinition(variable);
+  cmValue cacheValue = status.GetMakefile().GetDefinition(variable);
 
   // if there is no old value then return
   if (!cacheValue) {
index 4dfdfae..26f255d 100644 (file)
@@ -236,7 +236,6 @@ bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
   cmGlobalGenerator* gg = this->GetMakefile()->GetGlobalGenerator();
 
   // Add newer Visual Studio paths
-  AddVisualStudioPath(paths, "Visual Studio 17 ", 17, gg);
   AddVisualStudioPath(paths, "Visual Studio 16 ", 16, gg);
   AddVisualStudioPath(paths, "Visual Studio 15 ", 15, gg);
 
index a58be62..1bb459c 100644 (file)
@@ -8,9 +8,9 @@
 
 #include "cmFindCommon.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 cmSearchPath::cmSearchPath(cmFindCommon* findCmd)
   : FC(findCmd)
@@ -78,7 +78,7 @@ void cmSearchPath::AddCMakePath(const std::string& variable)
   assert(this->FC != nullptr);
 
   // Get a path from a CMake variable.
-  if (cmProp value = this->FC->Makefile->GetDefinition(variable)) {
+  if (cmValue value = this->FC->Makefile->GetDefinition(variable)) {
     std::vector<std::string> expanded = cmExpandedList(*value);
 
     for (std::string const& p : expanded) {
@@ -102,7 +102,7 @@ void cmSearchPath::AddCMakePrefixPath(const std::string& variable)
   assert(this->FC != nullptr);
 
   // Get a path from a CMake variable.
-  if (cmProp value = this->FC->Makefile->GetDefinition(variable)) {
+  if (cmValue value = this->FC->Makefile->GetDefinition(variable)) {
     std::vector<std::string> expanded = cmExpandedList(*value);
 
     this->AddPrefixPaths(
@@ -179,7 +179,7 @@ void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths,
       dir += "/";
     }
     if (subdir == "include" || subdir == "lib") {
-      cmProp arch =
+      cmValue arch =
         this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
       if (cmNonempty(arch)) {
         if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") &&
index 52b1a44..17285e7 100644 (file)
@@ -4,15 +4,16 @@
 
 #include <algorithm>
 
+#include <cm/string_view>
 #include <cmext/string_view>
 
 #include "cmArgumentParser.h"
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 // cmSeparateArgumentsCommand
 bool cmSeparateArgumentsCommand(std::vector<std::string> const& args,
@@ -27,7 +28,7 @@ bool cmSeparateArgumentsCommand(std::vector<std::string> const& args,
 
   if (args.size() == 1) {
     // Original space-replacement version of command.
-    if (cmProp def = status.GetMakefile().GetDefinition(var)) {
+    if (cmValue def = status.GetMakefile().GetDefinition(var)) {
       std::string value = *def;
       std::replace(value.begin(), value.end(), ' ', ';');
       status.GetMakefile().AddDefinition(var, value);
@@ -81,7 +82,7 @@ bool cmSeparateArgumentsCommand(std::vector<std::string> const& args,
   }
 
   if (unparsedArguments.empty()) {
-    status.GetMakefile().AddDefinition(var, {});
+    status.GetMakefile().AddDefinition(var, cm::string_view{});
     return true;
   }
 
index 354b4c3..ce0cb25 100644 (file)
@@ -5,12 +5,12 @@
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 // cmSetCommand
 bool cmSetCommand(std::vector<std::string> const& args,
@@ -136,7 +136,7 @@ bool cmSetCommand(std::vector<std::string> const& args,
 
   // see if this is already in the cache
   cmState* state = status.GetMakefile().GetState();
-  cmProp existingValue = state->GetCacheEntryValue(variable);
+  cmValue existingValue = state->GetCacheEntryValue(variable);
   if (existingValue &&
       (state->GetCacheEntryType(variable) != cmStateEnums::UNINITIALIZED)) {
     // if the set is trying to CACHE the value but the value
index 07ad246..9adf537 100644 (file)
@@ -32,7 +32,7 @@ bool cmSetDirectoryPropertiesCommand(std::vector<std::string> const& args,
         "Commands and macros cannot be set using SET_CMAKE_PROPERTIES");
       return false;
     }
-    status.GetMakefile().SetProperty(prop, (iter + 1)->c_str());
+    status.GetMakefile().SetProperty(prop, *(iter + 1));
   }
 
   return true;
index c899053..db10cd4 100644 (file)
@@ -21,6 +21,7 @@
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTest.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 namespace {
@@ -116,7 +117,7 @@ bool HandleSourceFileDirectoryScopes(
           "given non-existent target for TARGET_DIRECTORY ", target_name));
         return false;
       }
-      cmProp target_source_dir = target->GetProperty("BINARY_DIR");
+      cmValue target_source_dir = target->GetProperty("BINARY_DIR");
       cmMakefile* target_dir_mf =
         status.GetMakefile().GetGlobalGenerator()->FindMakefile(
           *target_source_dir);
@@ -294,7 +295,7 @@ bool HandleAndValidateSourceFilePropertyGENERATED(
         sf->SetProperty("GENERATED", nullptr);
         break;
       case PropertyOp::Set:
-        sf->SetProperty("GENERATED", propertyValue.c_str());
+        sf->SetProperty("GENERATED", propertyValue);
         break;
     }
   } else {
@@ -474,7 +475,7 @@ bool HandleGlobalMode(cmExecutionStatus& status,
     if (remove) {
       cm->SetProperty(propertyName, nullptr);
     } else {
-      cm->SetProperty(propertyName, propertyValue.c_str());
+      cm->SetProperty(propertyName, propertyValue);
     }
   }
 
@@ -520,7 +521,7 @@ bool HandleDirectoryMode(cmExecutionStatus& status,
     if (remove) {
       mf->SetProperty(propertyName, nullptr);
     } else {
-      mf->SetProperty(propertyName, propertyValue.c_str());
+      mf->SetProperty(propertyName, propertyValue);
     }
   }
 
@@ -631,7 +632,7 @@ bool HandleSource(cmSourceFile* sf, const std::string& propertyName,
     if (remove) {
       sf->SetProperty(propertyName, nullptr);
     } else {
-      sf->SetProperty(propertyName, propertyValue.c_str());
+      sf->SetProperty(propertyName, propertyValue);
     }
   }
   return true;
@@ -681,7 +682,7 @@ bool HandleTest(cmTest* test, const std::string& propertyName,
     if (remove) {
       test->SetProperty(propertyName, nullptr);
     } else {
-      test->SetProperty(propertyName, propertyValue.c_str());
+      test->SetProperty(propertyName, propertyValue);
     }
   }
 
@@ -719,7 +720,7 @@ bool HandleCacheMode(cmExecutionStatus& status,
   for (std::string const& name : names) {
     // Get the source file.
     cmake* cm = status.GetMakefile().GetCMakeInstance();
-    cmProp existingValue = cm->GetState()->GetCacheEntryValue(name);
+    cmValue existingValue = cm->GetState()->GetCacheEntryValue(name);
     if (existingValue) {
       if (!HandleCacheEntry(name, status.GetMakefile(), propertyName,
                             propertyValue, appendAsString, appendMode,
index 237b67f..ab93ddb 100644 (file)
@@ -173,7 +173,7 @@ static bool RunCommandForScope(
           SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED(
             sf, *(k + 1));
         } else {
-          sf->SetProperty(*k, (k + 1)->c_str());
+          sf->SetProperty(*k, *(k + 1));
         }
       }
     }
index c4bff76..a17c964 100644 (file)
@@ -37,7 +37,7 @@ bool cmSetTestsPropertiesCommand(std::vector<std::string> const& args,
       // loop through all the props and set them
       for (auto k = propsIter + 1; k != args.end(); k += 2) {
         if (!k->empty()) {
-          test->SetProperty(*k, (k + 1)->c_str());
+          test->SetProperty(*k, *(k + 1));
         }
       }
     } else {
index 58af8f0..61d1c30 100644 (file)
@@ -6,10 +6,9 @@
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
-#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 // cmSiteNameCommand
 bool cmSiteNameCommand(std::vector<std::string> const& args,
@@ -27,12 +26,12 @@ bool cmSiteNameCommand(std::vector<std::string> const& args,
   paths.emplace_back("/sbin");
   paths.emplace_back("/usr/local/bin");
 
-  cmProp cacheValue = status.GetMakefile().GetDefinition(args[0]);
+  cmValue cacheValue = status.GetMakefile().GetDefinition(args[0]);
   if (cacheValue) {
     return true;
   }
 
-  cmProp temp = status.GetMakefile().GetDefinition("HOSTNAME");
+  cmValue temp = status.GetMakefile().GetDefinition("HOSTNAME");
   std::string hostname_cmd;
   if (temp) {
     hostname_cmd = *temp;
index 3f3c8d5..3fa0051 100644 (file)
@@ -13,6 +13,7 @@
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name,
@@ -53,7 +54,7 @@ std::string cmSourceFile::GetObjectLibrary() const
 std::string const& cmSourceFile::GetOrDetermineLanguage()
 {
   // If the language was set explicitly by the user then use it.
-  if (cmProp lang = this->GetProperty(propLANGUAGE)) {
+  if (cmValue lang = this->GetProperty(propLANGUAGE)) {
     // Assign to member in order to return a reference.
     this->Language = *lang;
     return this->Language;
@@ -84,7 +85,7 @@ std::string const& cmSourceFile::GetOrDetermineLanguage()
 std::string cmSourceFile::GetLanguage() const
 {
   // If the language was set explicitly by the user then use it.
-  if (cmProp lang = this->GetProperty(propLANGUAGE)) {
+  if (cmValue lang = this->GetProperty(propLANGUAGE)) {
     return *lang;
   }
 
@@ -269,7 +270,8 @@ bool cmSourceFile::Matches(cmSourceFileLocation const& loc)
   return this->Location.Matches(loc);
 }
 
-void cmSourceFile::SetProperty(const std::string& prop, const char* value)
+template <typename ValueType>
+void cmSourceFile::StoreProperty(const std::string& prop, ValueType value)
 {
   if (prop == propINCLUDE_DIRECTORIES) {
     this->IncludeDirectories.clear();
@@ -294,6 +296,15 @@ void cmSourceFile::SetProperty(const std::string& prop, const char* value)
   }
 }
 
+void cmSourceFile::SetProperty(const std::string& prop, const char* value)
+{
+  this->StoreProperty(prop, value);
+}
+void cmSourceFile::SetProperty(const std::string& prop, cmValue value)
+{
+  this->StoreProperty(prop, value);
+}
+
 void cmSourceFile::AppendProperty(const std::string& prop,
                                   const std::string& value, bool asString)
 {
@@ -317,7 +328,7 @@ void cmSourceFile::AppendProperty(const std::string& prop,
   }
 }
 
-cmProp cmSourceFile::GetPropertyForUser(const std::string& prop)
+cmValue cmSourceFile::GetPropertyForUser(const std::string& prop)
 {
   // This method is a consequence of design history and backwards
   // compatibility.  GetProperty is (and should be) a const method.
@@ -342,7 +353,7 @@ cmProp cmSourceFile::GetPropertyForUser(const std::string& prop)
   // if it is requested by the user.
   if (prop == propLANGUAGE) {
     // The pointer is valid until `this->Language` is modified.
-    return &this->GetOrDetermineLanguage();
+    return cmValue(this->GetOrDetermineLanguage());
   }
 
   // Special handling for GENERATED property.
@@ -355,23 +366,23 @@ cmProp cmSourceFile::GetPropertyForUser(const std::string& prop)
           (policyStatus == cmPolicies::WARN || policyStatus == cmPolicies::OLD)
             ? CheckScope::GlobalAndLocal
             : CheckScope::Global)) {
-      return &propTRUE;
+      return cmValue(propTRUE);
     }
-    return &propFALSE;
+    return cmValue(propFALSE);
   }
 
   // Perform the normal property lookup.
   return this->GetProperty(prop);
 }
 
-cmProp cmSourceFile::GetProperty(const std::string& prop) const
+cmValue cmSourceFile::GetProperty(const std::string& prop) const
 {
   // Check for computed properties.
   if (prop == propLOCATION) {
     if (this->FullPath.empty()) {
       return nullptr;
     }
-    return &this->FullPath;
+    return cmValue(this->FullPath);
   }
 
   // Check for the properties with backtraces.
@@ -382,7 +393,7 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const
 
     static std::string output;
     output = cmJoin(this->IncludeDirectories, ";");
-    return &output;
+    return cmValue(output);
   }
 
   if (prop == propCOMPILE_OPTIONS) {
@@ -392,7 +403,7 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const
 
     static std::string output;
     output = cmJoin(this->CompileOptions, ";");
-    return &output;
+    return cmValue(output);
   }
 
   if (prop == propCOMPILE_DEFINITIONS) {
@@ -402,10 +413,10 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const
 
     static std::string output;
     output = cmJoin(this->CompileDefinitions, ";");
-    return &output;
+    return cmValue(output);
   }
 
-  cmProp retVal = this->Properties.GetPropertyValue(prop);
+  cmValue retVal = this->Properties.GetPropertyValue(prop);
   if (!retVal) {
     cmMakefile const* mf = this->Location.GetMakefile();
     const bool chain =
@@ -421,7 +432,7 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const
 
 const std::string& cmSourceFile::GetSafeProperty(const std::string& prop) const
 {
-  cmProp ret = this->GetProperty(prop);
+  cmValue ret = this->GetProperty(prop);
   if (ret) {
     return *ret;
   }
index 32ed687..c1c5201 100644 (file)
 
 #include "cmCustomCommand.h"
 #include "cmListFileCache.h"
-#include "cmProperty.h"
 #include "cmPropertyMap.h"
 #include "cmSourceFileLocation.h"
 #include "cmSourceFileLocationKind.h"
+#include "cmValue.h"
 
 class cmMakefile;
 
@@ -42,17 +42,22 @@ public:
 
   //! Set/Get a property of this source file
   void SetProperty(const std::string& prop, const char* value);
+  void SetProperty(const std::string& prop, cmValue value);
+  void SetProperty(const std::string& prop, const std::string& value)
+  {
+    this->SetProperty(prop, cmValue(value));
+  }
   void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString = false);
   //! Might return a nullptr if the property is not set or invalid
-  cmProp GetProperty(const std::string& prop) const;
+  cmValue GetProperty(const std::string& prop) const;
   //! Always returns a valid pointer
   const std::string& GetSafeProperty(const std::string& prop) const;
   bool GetPropertyAsBool(const std::string& prop) const;
 
   /** Implement getting a property when called from a CMake language
       command like get_property or get_source_file_property.  */
-  cmProp GetPropertyForUser(const std::string& prop);
+  cmValue GetPropertyForUser(const std::string& prop);
 
   /// Marks this file as generated
   /**
@@ -145,6 +150,9 @@ public:
   std::string GetObjectLibrary() const;
 
 private:
+  template <typename ValueType>
+  void StoreProperty(const std::string& prop, ValueType value);
+
   cmSourceFileLocation Location;
   cmPropertyMap Properties;
   std::unique_ptr<cmCustomCommand> CustomCommand;
index 37ed4c1..61416e0 100644 (file)
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
+#include "cmPolicies.h"
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 namespace {
@@ -57,10 +58,10 @@ int ParseStd(std::string const& level)
   return -1;
 }
 
-struct StanardLevelComputer
+struct StandardLevelComputer
 {
-  explicit StanardLevelComputer(std::string lang, std::vector<int> levels,
-                                std::vector<std::string> levelsStr)
+  explicit StandardLevelComputer(std::string lang, std::vector<int> levels,
+                                 std::vector<std::string> levelsStr)
     : Language(std::move(lang))
     , Levels(std::move(levels))
     , LevelsAsStrings(std::move(levelsStr))
@@ -76,37 +77,74 @@ struct StanardLevelComputer
     const auto& stds = this->Levels;
     const auto& stdsStrings = this->LevelsAsStrings;
 
-    cmProp defaultStd = makefile->GetDefinition(
+    cmValue defaultStd = makefile->GetDefinition(
       cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT"));
     if (!cmNonempty(defaultStd)) {
       // this compiler has no notion of language standard levels
       return std::string{};
     }
 
+    cmPolicies::PolicyStatus const cmp0128{ makefile->GetPolicyStatus(
+      cmPolicies::CMP0128) };
+    bool const defaultExt{ cmIsOn(*makefile->GetDefinition(
+      cmStrCat("CMAKE_", this->Language, "_EXTENSIONS_DEFAULT"))) };
     bool ext = true;
-    if (cmProp extPropValue = target->GetLanguageExtensions(this->Language)) {
-      if (cmIsOff(*extPropValue)) {
-        ext = false;
-      }
+
+    if (cmp0128 == cmPolicies::NEW) {
+      ext = defaultExt;
     }
 
-    cmProp standardProp = target->GetLanguageStandard(this->Language, config);
+    if (cmValue extPropValue = target->GetLanguageExtensions(this->Language)) {
+      ext = cmIsOn(*extPropValue);
+    }
+
+    std::string const type{ ext ? "EXTENSION" : "STANDARD" };
+
+    cmValue standardProp = target->GetLanguageStandard(this->Language, config);
     if (!standardProp) {
-      if (ext) {
-        // No language standard is specified and extensions are not disabled.
-        // Check if this compiler needs a flag to enable extensions.
-        return cmStrCat("CMAKE_", this->Language, "_EXTENSION_COMPILE_OPTION");
+      if (cmp0128 == cmPolicies::NEW) {
+        // Add extension flag if compiler's default doesn't match.
+        if (ext != defaultExt) {
+          return cmStrCat("CMAKE_", this->Language, *defaultStd, "_", type,
+                          "_COMPILE_OPTION");
+        }
+      } else {
+        if (cmp0128 == cmPolicies::WARN &&
+            makefile->PolicyOptionalWarningEnabled(
+              "CMAKE_POLICY_WARNING_CMP0128") &&
+            ext != defaultExt) {
+          const char* state{};
+          if (ext) {
+            if (!makefile->GetDefinition(cmStrCat(
+                  "CMAKE_", this->Language, "_EXTENSION_COMPILE_OPTION"))) {
+              state = "enabled";
+            }
+          } else {
+            state = "disabled";
+          }
+          if (state) {
+            makefile->IssueMessage(
+              MessageType::AUTHOR_WARNING,
+              cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0128),
+                       "\nFor compatibility with older versions of CMake, "
+                       "compiler extensions won't be ",
+                       state, "."));
+          }
+        }
+
+        if (ext) {
+          return cmStrCat("CMAKE_", this->Language,
+                          "_EXTENSION_COMPILE_OPTION");
+        }
       }
       return std::string{};
     }
 
-    std::string const type = ext ? "EXTENSION" : "STANDARD";
-
     if (target->GetLanguageStandardRequired(this->Language)) {
       std::string option_flag = cmStrCat(
         "CMAKE_", this->Language, *standardProp, "_", type, "_COMPILE_OPTION");
 
-      cmProp opt = target->Target->GetMakefile()->GetDefinition(option_flag);
+      cmValue opt = target->Target->GetMakefile()->GetDefinition(option_flag);
       if (!opt) {
         std::ostringstream e;
         e << "Target \"" << target->GetName()
@@ -121,6 +159,25 @@ struct StanardLevelComputer
       return option_flag;
     }
 
+    // If the request matches the compiler's defaults we don't need to add
+    // anything.
+    if (*standardProp == *defaultStd && ext == defaultExt) {
+      if (cmp0128 == cmPolicies::NEW) {
+        return std::string{};
+      }
+
+      if (cmp0128 == cmPolicies::WARN &&
+          makefile->PolicyOptionalWarningEnabled(
+            "CMAKE_POLICY_WARNING_CMP0128")) {
+        makefile->IssueMessage(
+          MessageType::AUTHOR_WARNING,
+          cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0128),
+                   "\nFor compatibility with older versions of CMake, "
+                   "unnecessary flags for language standard or compiler "
+                   "extensions may be added."));
+      }
+    }
+
     std::string standardStr(*standardProp);
     if (this->Language == "CUDA" && standardStr == "98") {
       standardStr = "03";
@@ -147,17 +204,18 @@ struct StanardLevelComputer
       return std::string{};
     }
 
-    // If the standard requested is older than the compiler's default
-    // then we need to use a flag to change it.
-    if (stdIt <= defaultStdIt) {
+    // If the standard requested is older than the compiler's default or the
+    // extension mode doesn't match then we need to use a flag.
+    if (stdIt < defaultStdIt ||
+        (cmp0128 == cmPolicies::NEW && ext != defaultExt)) {
       auto offset = std::distance(cm::cbegin(stds), stdIt);
       return cmStrCat("CMAKE_", this->Language, stdsStrings[offset], "_", type,
                       "_COMPILE_OPTION");
     }
 
-    // The standard requested is at least as new as the compiler's default,
-    // and the standard request is not required.  Decay to the newest standard
-    // for which a flag is defined.
+    // The compiler's default is at least as new as the requested standard,
+    // and the requested standard is not required.  Decay to the newest
+    // standard for which a flag is defined.
     for (; defaultStdIt < stdIt; --stdIt) {
       auto offset = std::distance(cm::cbegin(stds), stdIt);
       std::string option_flag =
@@ -174,7 +232,7 @@ struct StanardLevelComputer
   bool GetNewRequiredStandard(cmMakefile* makefile,
                               std::string const& targetName,
                               const std::string& feature,
-                              cmProp currentLangStandardValue,
+                              cmValue currentLangStandardValue,
                               std::string& newRequiredStandard,
                               std::string* error) const
   {
@@ -186,9 +244,9 @@ struct StanardLevelComputer
 
     auto needed = this->HighestStandardNeeded(makefile, feature);
 
-    cmProp existingStandard = currentLangStandardValue;
+    cmValue existingStandard = currentLangStandardValue;
     if (!existingStandard) {
-      cmProp defaultStandard = makefile->GetDefinition(
+      cmValue defaultStandard = makefile->GetDefinition(
         cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT"));
       if (cmNonempty(defaultStandard)) {
         existingStandard = defaultStandard;
@@ -231,7 +289,7 @@ struct StanardLevelComputer
                              std::string const& config,
                              std::string const& feature) const
   {
-    cmProp defaultStandard = makefile->GetDefinition(
+    cmValue defaultStandard = makefile->GetDefinition(
       cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT"));
     if (!defaultStandard) {
       makefile->IssueMessage(
@@ -253,7 +311,7 @@ struct StanardLevelComputer
       return false;
     }
 
-    cmProp existingStandard =
+    cmValue existingStandard =
       target->GetLanguageStandard(this->Language, config);
     if (!existingStandard) {
       existingStandard = defaultStandard;
@@ -283,7 +341,7 @@ struct StanardLevelComputer
     std::string prefix = cmStrCat("CMAKE_", this->Language);
     StandardNeeded maxLevel = { -1, -1 };
     for (size_t i = 0; i < this->Levels.size(); ++i) {
-      if (cmProp prop = makefile->GetDefinition(
+      if (cmValue prop = makefile->GetDefinition(
             cmStrCat(prefix, this->LevelsAsStrings[i], "_COMPILE_FEATURES"))) {
         std::vector<std::string> props = cmExpandedList(*prop);
         if (cm::contains(props, feature)) {
@@ -308,31 +366,33 @@ struct StanardLevelComputer
   std::vector<std::string> LevelsAsStrings;
 };
 
-std::unordered_map<std::string, StanardLevelComputer> StandardComputerMapping =
-  { { "C",
-      StanardLevelComputer{
+std::unordered_map<std::string, StandardLevelComputer>
+  StandardComputerMapping = {
+    { "C",
+      StandardLevelComputer{
         "C", std::vector<int>{ 90, 99, 11, 17, 23 },
         std::vector<std::string>{ "90", "99", "11", "17", "23" } } },
     { "CXX",
-      StanardLevelComputer{
+      StandardLevelComputer{
         "CXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 },
         std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } },
     { "CUDA",
-      StanardLevelComputer{
+      StandardLevelComputer{
         "CUDA", std::vector<int>{ 03, 11, 14, 17, 20, 23 },
         std::vector<std::string>{ "03", "11", "14", "17", "20", "23" } } },
     { "OBJC",
-      StanardLevelComputer{
+      StandardLevelComputer{
         "OBJC", std::vector<int>{ 90, 99, 11, 17, 23 },
         std::vector<std::string>{ "90", "99", "11", "17", "23" } } },
     { "OBJCXX",
-      StanardLevelComputer{
+      StandardLevelComputer{
         "OBJCXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 },
         std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } },
     { "HIP",
-      StanardLevelComputer{
+      StandardLevelComputer{
         "HIP", std::vector<int>{ 98, 11, 14, 17, 20, 23 },
-        std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } } };
+        std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } }
+  };
 }
 
 std::string cmStandardLevelResolver::GetCompileOptionDef(
@@ -387,7 +447,11 @@ bool cmStandardLevelResolver::CheckCompileFeaturesAvailable(
     return false;
   }
 
-  const char* features = this->CompileFeaturesAvailable(lang, error);
+  if (!this->Makefile->GetGlobalGenerator()->GetLanguageEnabled(lang)) {
+    return true;
+  }
+
+  cmValue features = this->CompileFeaturesAvailable(lang, error);
   if (!features) {
     return false;
   }
@@ -465,7 +529,7 @@ bool cmStandardLevelResolver::CompileFeatureKnown(
   return false;
 }
 
-const char* cmStandardLevelResolver::CompileFeaturesAvailable(
+cmValue cmStandardLevelResolver::CompileFeaturesAvailable(
   const std::string& lang, std::string* error) const
 {
   if (!this->Makefile->GetGlobalGenerator()->GetLanguageEnabled(lang)) {
@@ -484,7 +548,7 @@ const char* cmStandardLevelResolver::CompileFeaturesAvailable(
     return nullptr;
   }
 
-  cmProp featuresKnown =
+  cmValue featuresKnown =
     this->Makefile->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES");
 
   if (!cmNonempty(featuresKnown)) {
@@ -507,12 +571,12 @@ const char* cmStandardLevelResolver::CompileFeaturesAvailable(
     }
     return nullptr;
   }
-  return cmToCStr(featuresKnown);
+  return featuresKnown;
 }
 
 bool cmStandardLevelResolver::GetNewRequiredStandard(
   const std::string& targetName, const std::string& feature,
-  cmProp currentLangStandardValue, std::string& newRequiredStandard,
+  cmValue currentLangStandardValue, std::string& newRequiredStandard,
   std::string* error) const
 {
   std::string lang;
index d84fbcb..4226456 100644 (file)
@@ -4,7 +4,7 @@
 
 #include <string>
 
-#include "cmProperty.h"
+#include "cmValue.h"
 
 class cmMakefile;
 class cmGeneratorTarget;
@@ -30,12 +30,12 @@ public:
                            const std::string& feature, std::string& lang,
                            std::string* error) const;
 
-  const char* CompileFeaturesAvailable(const std::string& lang,
-                                       std::string* error) const;
+  cmValue CompileFeaturesAvailable(const std::string& lang,
+                                   std::string* error) const;
 
   bool GetNewRequiredStandard(const std::string& targetName,
                               const std::string& feature,
-                              cmProp currentLangStandardValue,
+                              cmValue currentLangStandardValue,
                               std::string& newRequiredStandard,
                               std::string* error = nullptr) const;
 
index ce6eb31..e79949d 100644 (file)
@@ -26,7 +26,9 @@
 #include "cmSystemTools.h"
 #include "cmake.h"
 
-cmState::cmState()
+cmState::cmState(Mode mode, ProjectKind projectKind)
+  : StateMode(mode)
+  , StateProjectKind(projectKind)
 {
   this->CacheManager = cm::make_unique<cmCacheManager>();
   this->GlobVerificationManager = cm::make_unique<cmGlobVerificationManager>();
@@ -142,20 +144,20 @@ std::vector<std::string> cmState::GetCacheEntryKeys() const
   return this->CacheManager->GetCacheEntryKeys();
 }
 
-cmProp cmState::GetCacheEntryValue(std::string const& key) const
+cmValue cmState::GetCacheEntryValue(std::string const& key) const
 {
   return this->CacheManager->GetCacheEntryValue(key);
 }
 
 std::string cmState::GetSafeCacheEntryValue(std::string const& key) const
 {
-  if (cmProp val = this->GetCacheEntryValue(key)) {
+  if (cmValue val = this->GetCacheEntryValue(key)) {
     return *val;
   }
   return std::string();
 }
 
-cmProp cmState::GetInitializedCacheValue(std::string const& key) const
+cmValue cmState::GetInitializedCacheValue(std::string const& key) const
 {
   return this->CacheManager->GetInitializedCacheValue(key);
 }
@@ -192,8 +194,8 @@ std::vector<std::string> cmState::GetCacheEntryPropertyList(
   return this->CacheManager->GetCacheEntryPropertyList(key);
 }
 
-cmProp cmState::GetCacheEntryProperty(std::string const& key,
-                                      std::string const& propertyName)
+cmValue cmState::GetCacheEntryProperty(std::string const& key,
+                                       std::string const& propertyName)
 {
   return this->CacheManager->GetCacheEntryProperty(key, propertyName);
 }
@@ -204,7 +206,7 @@ bool cmState::GetCacheEntryPropertyAsBool(std::string const& key,
   return this->CacheManager->GetCacheEntryPropertyAsBool(key, propertyName);
 }
 
-void cmState::AddCacheEntry(const std::string& key, const char* value,
+void cmState::AddCacheEntry(const std::string& key, cmValue value,
                             const char* helpString,
                             cmStateEnums::CacheEntryType type)
 {
@@ -275,15 +277,10 @@ cmStateSnapshot cmState::Reset()
     cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>::iterator it =
       this->BuildsystemDirectory.Truncate();
     it->IncludeDirectories.clear();
-    it->IncludeDirectoryBacktraces.clear();
     it->CompileDefinitions.clear();
-    it->CompileDefinitionsBacktraces.clear();
     it->CompileOptions.clear();
-    it->CompileOptionsBacktraces.clear();
     it->LinkOptions.clear();
-    it->LinkOptionsBacktraces.clear();
     it->LinkDirectories.clear();
-    it->LinkDirectoriesBacktraces.clear();
     it->DirectoryEnd = pos;
     it->NormalTargetNames.clear();
     it->ImportedTargetNames.clear();
@@ -381,16 +378,6 @@ void cmState::ClearEnabledLanguages()
   this->EnabledLanguages.clear();
 }
 
-bool cmState::GetIsInTryCompile() const
-{
-  return this->IsInTryCompile;
-}
-
-void cmState::SetIsInTryCompile(bool b)
-{
-  this->IsInTryCompile = b;
-}
-
 bool cmState::GetIsGeneratorMultiConfig() const
 {
   return this->IsGeneratorMultiConfig;
@@ -466,7 +453,7 @@ void cmState::AddDisallowedCommand(std::string const& name,
         case cmPolicies::WARN:
           mf.IssueMessage(MessageType::AUTHOR_WARNING,
                           cmPolicies::GetPolicyWarning(policy));
-          break;
+          CM_FALLTHROUGH;
         case cmPolicies::OLD:
           break;
         case cmPolicies::REQUIRED_IF_USED:
@@ -485,7 +472,7 @@ void cmState::AddUnexpectedCommand(std::string const& name, const char* error)
     name,
     [name, error](std::vector<cmListFileArgument> const&,
                   cmExecutionStatus& status) -> bool {
-      cmProp versionValue =
+      cmValue versionValue =
         status.GetMakefile().GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION");
       if (name == "endif" &&
           (!versionValue || atof(versionValue->c_str()) <= 1.4)) {
@@ -577,6 +564,10 @@ void cmState::SetGlobalProperty(const std::string& prop, const char* value)
 {
   this->GlobalProperties.SetProperty(prop, value);
 }
+void cmState::SetGlobalProperty(const std::string& prop, cmValue value)
+{
+  this->GlobalProperties.SetProperty(prop, value);
+}
 
 void cmState::AppendGlobalProperty(const std::string& prop,
                                    const std::string& value, bool asString)
@@ -584,7 +575,7 @@ void cmState::AppendGlobalProperty(const std::string& prop,
   this->GlobalProperties.AppendProperty(prop, value, asString);
 }
 
-cmProp cmState::GetGlobalProperty(const std::string& prop)
+cmValue cmState::GetGlobalProperty(const std::string& prop)
 {
   if (prop == "CACHE_VARIABLES") {
     std::vector<std::string> cacheKeys = this->GetCacheEntryKeys();
@@ -593,8 +584,9 @@ cmProp cmState::GetGlobalProperty(const std::string& prop)
     std::vector<std::string> commands = this->GetCommandNames();
     this->SetGlobalProperty("COMMANDS", cmJoin(commands, ";").c_str());
   } else if (prop == "IN_TRY_COMPILE") {
-    this->SetGlobalProperty("IN_TRY_COMPILE",
-                            this->IsInTryCompile ? "1" : "0");
+    this->SetGlobalProperty(
+      "IN_TRY_COMPILE",
+      this->StateProjectKind == ProjectKind::TryCompile ? "1" : "0");
   } else if (prop == "GENERATOR_IS_MULTI_CONFIG") {
     this->SetGlobalProperty("GENERATOR_IS_MULTI_CONFIG",
                             this->IsGeneratorMultiConfig ? "1" : "0");
@@ -610,47 +602,47 @@ cmProp cmState::GetGlobalProperty(const std::string& prop)
   if (prop == "CMAKE_C_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmValue(s_out);
   }
   if (prop == "CMAKE_C90_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_C90_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmValue(s_out);
   }
   if (prop == "CMAKE_C99_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_C99_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmValue(s_out);
   }
   if (prop == "CMAKE_C11_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_C11_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmValue(s_out);
   }
   if (prop == "CMAKE_CXX_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmValue(s_out);
   }
   if (prop == "CMAKE_CXX98_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_CXX98_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmValue(s_out);
   }
   if (prop == "CMAKE_CXX11_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_CXX11_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmValue(s_out);
   }
   if (prop == "CMAKE_CXX14_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmValue(s_out);
   }
   if (prop == "CMAKE_CUDA_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_CUDA_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmValue(s_out);
   }
 
 #undef STRING_LIST_ELEMENT
@@ -771,17 +763,12 @@ unsigned int cmState::GetCacheMinorVersion() const
 
 cmState::Mode cmState::GetMode() const
 {
-  return this->CurrentMode;
+  return this->StateMode;
 }
 
 std::string cmState::GetModeString() const
 {
-  return ModeToString(this->CurrentMode);
-}
-
-void cmState::SetMode(cmState::Mode mode)
-{
-  this->CurrentMode = mode;
+  return ModeToString(this->StateMode);
 }
 
 std::string cmState::ModeToString(cmState::Mode mode)
@@ -803,6 +790,11 @@ std::string cmState::ModeToString(cmState::Mode mode)
   return "UNKNOWN";
 }
 
+cmState::ProjectKind cmState::GetProjectKind() const
+{
+  return this->StateProjectKind;
+}
+
 std::string const& cmState::GetBinaryDirectory() const
 {
   return this->BinaryDirectory;
index 9951b9a..a1666ca 100644 (file)
@@ -21,6 +21,7 @@
 #include "cmPropertyMap.h"
 #include "cmStatePrivate.h"
 #include "cmStateTypes.h"
+#include "cmValue.h"
 
 class cmCacheManager;
 class cmCommand;
@@ -35,12 +36,6 @@ class cmState
   friend class cmStateSnapshot;
 
 public:
-  cmState();
-  ~cmState();
-
-  cmState(const cmState&) = delete;
-  cmState& operator=(const cmState&) = delete;
-
   enum Mode
   {
     Unknown,
@@ -51,6 +46,18 @@ public:
     CPack,
   };
 
+  enum class ProjectKind
+  {
+    Normal,
+    TryCompile,
+  };
+
+  cmState(Mode mode, ProjectKind projectKind = ProjectKind::Normal);
+  ~cmState();
+
+  cmState(const cmState&) = delete;
+  cmState& operator=(const cmState&) = delete;
+
   static const std::string& GetTargetTypeName(
     cmStateEnums::TargetType targetType);
 
@@ -92,9 +99,9 @@ public:
   bool IsCacheLoaded() const;
 
   std::vector<std::string> GetCacheEntryKeys() const;
-  cmProp GetCacheEntryValue(std::string const& key) const;
+  cmValue GetCacheEntryValue(std::string const& key) const;
   std::string GetSafeCacheEntryValue(std::string const& key) const;
-  cmProp GetInitializedCacheValue(std::string const& key) const;
+  cmValue GetInitializedCacheValue(std::string const& key) const;
   cmStateEnums::CacheEntryType GetCacheEntryType(std::string const& key) const;
   void SetCacheEntryValue(std::string const& key, std::string const& value);
 
@@ -106,8 +113,8 @@ public:
   void SetCacheEntryBoolProperty(std::string const& key,
                                  std::string const& propertyName, bool value);
   std::vector<std::string> GetCacheEntryPropertyList(std::string const& key);
-  cmProp GetCacheEntryProperty(std::string const& key,
-                               std::string const& propertyName);
+  cmValue GetCacheEntryProperty(std::string const& key,
+                                std::string const& propertyName);
   bool GetCacheEntryPropertyAsBool(std::string const& key,
                                    std::string const& propertyName);
   void AppendCacheEntryProperty(std::string const& key,
@@ -141,9 +148,6 @@ public:
   void SetEnabledLanguages(std::vector<std::string> const& langs);
   void ClearEnabledLanguages();
 
-  bool GetIsInTryCompile() const;
-  void SetIsInTryCompile(bool b);
-
   bool GetIsGeneratorMultiConfig() const;
   void SetIsGeneratorMultiConfig(bool b);
 
@@ -175,9 +179,10 @@ public:
   std::vector<std::string> GetCommandNames() const;
 
   void SetGlobalProperty(const std::string& prop, const char* value);
+  void SetGlobalProperty(const std::string& prop, cmValue value);
   void AppendGlobalProperty(const std::string& prop, const std::string& value,
                             bool asString = false);
-  cmProp GetGlobalProperty(const std::string& prop);
+  cmValue GetGlobalProperty(const std::string& prop);
   bool GetGlobalPropertyAsBool(const std::string& prop);
 
   std::string const& GetSourceDirectory() const;
@@ -207,13 +212,26 @@ public:
 
   Mode GetMode() const;
   std::string GetModeString() const;
-  void SetMode(Mode mode);
 
   static std::string ModeToString(Mode mode);
 
+  ProjectKind GetProjectKind() const;
+
 private:
   friend class cmake;
   void AddCacheEntry(const std::string& key, const char* value,
+                     const char* helpString, cmStateEnums::CacheEntryType type)
+  {
+    this->AddCacheEntry(key,
+                        value ? cmValue(std::string(value)) : cmValue(nullptr),
+                        helpString, type);
+  }
+  void AddCacheEntry(const std::string& key, const std::string& value,
+                     const char* helpString, cmStateEnums::CacheEntryType type)
+  {
+    this->AddCacheEntry(key, cmValue(value), helpString, type);
+  }
+  void AddCacheEntry(const std::string& key, cmValue value,
                      const char* helpString,
                      cmStateEnums::CacheEntryType type);
 
@@ -248,7 +266,6 @@ private:
 
   std::string SourceDirectory;
   std::string BinaryDirectory;
-  bool IsInTryCompile = false;
   bool IsGeneratorMultiConfig = false;
   bool WindowsShell = false;
   bool WindowsVSIDE = false;
@@ -258,5 +275,6 @@ private:
   bool NMake = false;
   bool MSYSShell = false;
   bool NinjaMulti = false;
-  Mode CurrentMode = Unknown;
+  Mode StateMode = Unknown;
+  ProjectKind StateProjectKind = ProjectKind::Normal;
 };
index c898dd4..b42e5c3 100644 (file)
@@ -19,7 +19,9 @@
 #include "cmState.h"
 #include "cmStatePrivate.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 static std::string const kBINARY_DIR = "BINARY_DIR";
 static std::string const kBUILDSYSTEM_TARGETS = "BUILDSYSTEM_TARGETS";
@@ -63,7 +65,7 @@ cmStateDirectory::cmStateDirectory(
 }
 
 template <typename T, typename U>
-cmStringRange GetPropertyContent(T const& content, U contentEndPosition)
+cmBTStringRange GetPropertyContent(T const& content, U contentEndPosition)
 {
   auto end = content.begin() + contentEndPosition;
 
@@ -73,88 +75,59 @@ cmStringRange GetPropertyContent(T const& content, U contentEndPosition)
   return cmMakeRange(rbegin.base(), end);
 }
 
-template <typename T, typename U, typename V>
-cmBacktraceRange GetPropertyBacktraces(T const& content, U const& backtraces,
-                                       V contentEndPosition)
-{
-  auto entryEnd = content.begin() + contentEndPosition;
-
-  auto rbegin = cm::make_reverse_iterator(entryEnd);
-  rbegin = std::find(rbegin, content.rend(), cmPropertySentinal);
-
-  auto it = backtraces.begin() + std::distance(content.begin(), rbegin.base());
-
-  auto end = backtraces.end();
-  return cmMakeRange(it, end);
-}
-
-template <typename T, typename U, typename V>
-void AppendEntry(T& content, U& backtraces, V& endContentPosition,
-                 const std::string& value, const cmListFileBacktrace& lfbt)
+template <typename T, typename U>
+void AppendEntry(T& content, U& endContentPosition,
+                 const BT<std::string>& value)
 {
-  if (value.empty()) {
+  if (value.Value.empty()) {
     return;
   }
 
   assert(endContentPosition == content.size());
 
   content.push_back(value);
-  backtraces.push_back(lfbt);
 
   endContentPosition = content.size();
 }
 
-template <typename T, typename U, typename V>
-void SetContent(T& content, U& backtraces, V& endContentPosition,
-                const std::string& vec, const cmListFileBacktrace& lfbt)
+template <typename T, typename U>
+void SetContent(T& content, U& endContentPosition, const BT<std::string>& vec)
 {
   assert(endContentPosition == content.size());
 
   content.resize(content.size() + 2);
-  backtraces.resize(backtraces.size() + 2);
 
   content.back() = vec;
-  backtraces.back() = lfbt;
 
   endContentPosition = content.size();
 }
 
-template <typename T, typename U, typename V>
-void ClearContent(T& content, U& backtraces, V& endContentPosition)
+template <typename T, typename U>
+void ClearContent(T& content, U& endContentPosition)
 {
   assert(endContentPosition == content.size());
 
   content.resize(content.size() + 1);
-  backtraces.resize(backtraces.size() + 1);
 
   endContentPosition = content.size();
 }
 
-cmStringRange cmStateDirectory::GetIncludeDirectoriesEntries() const
+cmBTStringRange cmStateDirectory::GetIncludeDirectoriesEntries() const
 {
   return GetPropertyContent(
     this->DirectoryState->IncludeDirectories,
     this->Snapshot_.Position->IncludeDirectoryPosition);
 }
 
-cmBacktraceRange cmStateDirectory::GetIncludeDirectoriesEntryBacktraces() const
-{
-  return GetPropertyBacktraces(
-    this->DirectoryState->IncludeDirectories,
-    this->DirectoryState->IncludeDirectoryBacktraces,
-    this->Snapshot_.Position->IncludeDirectoryPosition);
-}
-
 void cmStateDirectory::AppendIncludeDirectoriesEntry(
-  const std::string& vec, const cmListFileBacktrace& lfbt)
+  const BT<std::string>& vec)
 {
   AppendEntry(this->DirectoryState->IncludeDirectories,
-              this->DirectoryState->IncludeDirectoryBacktraces,
-              this->Snapshot_.Position->IncludeDirectoryPosition, vec, lfbt);
+              this->Snapshot_.Position->IncludeDirectoryPosition, vec);
 }
 
 void cmStateDirectory::PrependIncludeDirectoriesEntry(
-  const std::string& vec, const cmListFileBacktrace& lfbt)
+  const BT<std::string>& vec)
 {
   auto entryEnd = this->DirectoryState->IncludeDirectories.begin() +
     this->Snapshot_.Position->IncludeDirectoryPosition;
@@ -164,167 +137,111 @@ void cmStateDirectory::PrependIncludeDirectoriesEntry(
   rbegin = std::find(rbegin, rend, cmPropertySentinal);
 
   auto entryIt = rbegin.base();
-  auto entryBegin = this->DirectoryState->IncludeDirectories.begin();
-
-  auto btIt = this->DirectoryState->IncludeDirectoryBacktraces.begin() +
-    std::distance(entryBegin, entryIt);
 
   this->DirectoryState->IncludeDirectories.insert(entryIt, vec);
-  this->DirectoryState->IncludeDirectoryBacktraces.insert(btIt, lfbt);
 
   this->Snapshot_.Position->IncludeDirectoryPosition =
     this->DirectoryState->IncludeDirectories.size();
 }
 
-void cmStateDirectory::SetIncludeDirectories(const std::string& vec,
-                                             const cmListFileBacktrace& lfbt)
+void cmStateDirectory::SetIncludeDirectories(const BT<std::string>& vec)
 {
   SetContent(this->DirectoryState->IncludeDirectories,
-             this->DirectoryState->IncludeDirectoryBacktraces,
-             this->Snapshot_.Position->IncludeDirectoryPosition, vec, lfbt);
+             this->Snapshot_.Position->IncludeDirectoryPosition, vec);
 }
 
 void cmStateDirectory::ClearIncludeDirectories()
 {
   ClearContent(this->DirectoryState->IncludeDirectories,
-               this->DirectoryState->IncludeDirectoryBacktraces,
                this->Snapshot_.Position->IncludeDirectoryPosition);
 }
 
-cmStringRange cmStateDirectory::GetCompileDefinitionsEntries() const
+cmBTStringRange cmStateDirectory::GetCompileDefinitionsEntries() const
 {
   return GetPropertyContent(
     this->DirectoryState->CompileDefinitions,
     this->Snapshot_.Position->CompileDefinitionsPosition);
 }
 
-cmBacktraceRange cmStateDirectory::GetCompileDefinitionsEntryBacktraces() const
-{
-  return GetPropertyBacktraces(
-    this->DirectoryState->CompileDefinitions,
-    this->DirectoryState->CompileDefinitionsBacktraces,
-    this->Snapshot_.Position->CompileDefinitionsPosition);
-}
-
 void cmStateDirectory::AppendCompileDefinitionsEntry(
-  const std::string& vec, const cmListFileBacktrace& lfbt)
+  const BT<std::string>& vec)
 {
   AppendEntry(this->DirectoryState->CompileDefinitions,
-              this->DirectoryState->CompileDefinitionsBacktraces,
-              this->Snapshot_.Position->CompileDefinitionsPosition, vec, lfbt);
+              this->Snapshot_.Position->CompileDefinitionsPosition, vec);
 }
 
-void cmStateDirectory::SetCompileDefinitions(const std::string& vec,
-                                             const cmListFileBacktrace& lfbt)
+void cmStateDirectory::SetCompileDefinitions(const BT<std::string>& vec)
 {
   SetContent(this->DirectoryState->CompileDefinitions,
-             this->DirectoryState->CompileDefinitionsBacktraces,
-             this->Snapshot_.Position->CompileDefinitionsPosition, vec, lfbt);
+             this->Snapshot_.Position->CompileDefinitionsPosition, vec);
 }
 
 void cmStateDirectory::ClearCompileDefinitions()
 {
   ClearContent(this->DirectoryState->CompileDefinitions,
-               this->DirectoryState->CompileDefinitionsBacktraces,
                this->Snapshot_.Position->CompileDefinitionsPosition);
 }
 
-cmStringRange cmStateDirectory::GetCompileOptionsEntries() const
+cmBTStringRange cmStateDirectory::GetCompileOptionsEntries() const
 {
   return GetPropertyContent(this->DirectoryState->CompileOptions,
                             this->Snapshot_.Position->CompileOptionsPosition);
 }
 
-cmBacktraceRange cmStateDirectory::GetCompileOptionsEntryBacktraces() const
-{
-  return GetPropertyBacktraces(
-    this->DirectoryState->CompileOptions,
-    this->DirectoryState->CompileOptionsBacktraces,
-    this->Snapshot_.Position->CompileOptionsPosition);
-}
-
-void cmStateDirectory::AppendCompileOptionsEntry(
-  const std::string& vec, const cmListFileBacktrace& lfbt)
+void cmStateDirectory::AppendCompileOptionsEntry(const BT<std::string>& vec)
 {
   AppendEntry(this->DirectoryState->CompileOptions,
-              this->DirectoryState->CompileOptionsBacktraces,
-              this->Snapshot_.Position->CompileOptionsPosition, vec, lfbt);
+              this->Snapshot_.Position->CompileOptionsPosition, vec);
 }
 
-void cmStateDirectory::SetCompileOptions(const std::string& vec,
-                                         const cmListFileBacktrace& lfbt)
+void cmStateDirectory::SetCompileOptions(const BT<std::string>& vec)
 {
   SetContent(this->DirectoryState->CompileOptions,
-             this->DirectoryState->CompileOptionsBacktraces,
-             this->Snapshot_.Position->CompileOptionsPosition, vec, lfbt);
+             this->Snapshot_.Position->CompileOptionsPosition, vec);
 }
 
 void cmStateDirectory::ClearCompileOptions()
 {
   ClearContent(this->DirectoryState->CompileOptions,
-               this->DirectoryState->CompileOptionsBacktraces,
                this->Snapshot_.Position->CompileOptionsPosition);
 }
 
-cmStringRange cmStateDirectory::GetLinkOptionsEntries() const
+cmBTStringRange cmStateDirectory::GetLinkOptionsEntries() const
 {
   return GetPropertyContent(this->DirectoryState->LinkOptions,
                             this->Snapshot_.Position->LinkOptionsPosition);
 }
 
-cmBacktraceRange cmStateDirectory::GetLinkOptionsEntryBacktraces() const
-{
-  return GetPropertyBacktraces(this->DirectoryState->LinkOptions,
-                               this->DirectoryState->LinkOptionsBacktraces,
-                               this->Snapshot_.Position->LinkOptionsPosition);
-}
-
-void cmStateDirectory::AppendLinkOptionsEntry(const std::string& vec,
-                                              const cmListFileBacktrace& lfbt)
+void cmStateDirectory::AppendLinkOptionsEntry(const BT<std::string>& vec)
 {
   AppendEntry(this->DirectoryState->LinkOptions,
-              this->DirectoryState->LinkOptionsBacktraces,
-              this->Snapshot_.Position->LinkOptionsPosition, vec, lfbt);
+              this->Snapshot_.Position->LinkOptionsPosition, vec);
 }
 
-void cmStateDirectory::SetLinkOptions(const std::string& vec,
-                                      const cmListFileBacktrace& lfbt)
+void cmStateDirectory::SetLinkOptions(const BT<std::string>& vec)
 {
   SetContent(this->DirectoryState->LinkOptions,
-             this->DirectoryState->LinkOptionsBacktraces,
-             this->Snapshot_.Position->LinkOptionsPosition, vec, lfbt);
+             this->Snapshot_.Position->LinkOptionsPosition, vec);
 }
 
 void cmStateDirectory::ClearLinkOptions()
 {
   ClearContent(this->DirectoryState->LinkOptions,
-               this->DirectoryState->LinkOptionsBacktraces,
                this->Snapshot_.Position->LinkOptionsPosition);
 }
 
-cmStringRange cmStateDirectory::GetLinkDirectoriesEntries() const
+cmBTStringRange cmStateDirectory::GetLinkDirectoriesEntries() const
 {
   return GetPropertyContent(this->DirectoryState->LinkDirectories,
                             this->Snapshot_.Position->LinkDirectoriesPosition);
 }
 
-cmBacktraceRange cmStateDirectory::GetLinkDirectoriesEntryBacktraces() const
-{
-  return GetPropertyBacktraces(
-    this->DirectoryState->LinkDirectories,
-    this->DirectoryState->LinkDirectoriesBacktraces,
-    this->Snapshot_.Position->LinkDirectoriesPosition);
-}
-
-void cmStateDirectory::AppendLinkDirectoriesEntry(
-  const std::string& vec, const cmListFileBacktrace& lfbt)
+void cmStateDirectory::AppendLinkDirectoriesEntry(const BT<std::string>& vec)
 {
   AppendEntry(this->DirectoryState->LinkDirectories,
-              this->DirectoryState->LinkDirectoriesBacktraces,
-              this->Snapshot_.Position->LinkDirectoriesPosition, vec, lfbt);
+              this->Snapshot_.Position->LinkDirectoriesPosition, vec);
 }
-void cmStateDirectory::PrependLinkDirectoriesEntry(
-  const std::string& vec, const cmListFileBacktrace& lfbt)
+void cmStateDirectory::PrependLinkDirectoriesEntry(const BT<std::string>& vec)
 {
   auto entryEnd = this->DirectoryState->LinkDirectories.begin() +
     this->Snapshot_.Position->LinkDirectoriesPosition;
@@ -334,42 +251,35 @@ void cmStateDirectory::PrependLinkDirectoriesEntry(
   rbegin = std::find(rbegin, rend, cmPropertySentinal);
 
   auto entryIt = rbegin.base();
-  auto entryBegin = this->DirectoryState->LinkDirectories.begin();
-
-  auto btIt = this->DirectoryState->LinkDirectoriesBacktraces.begin() +
-    std::distance(entryBegin, entryIt);
 
   this->DirectoryState->LinkDirectories.insert(entryIt, vec);
-  this->DirectoryState->LinkDirectoriesBacktraces.insert(btIt, lfbt);
 
   this->Snapshot_.Position->LinkDirectoriesPosition =
     this->DirectoryState->LinkDirectories.size();
 }
 
-void cmStateDirectory::SetLinkDirectories(const std::string& vec,
-                                          const cmListFileBacktrace& lfbt)
+void cmStateDirectory::SetLinkDirectories(const BT<std::string>& vec)
 {
   SetContent(this->DirectoryState->LinkDirectories,
-             this->DirectoryState->LinkDirectoriesBacktraces,
-             this->Snapshot_.Position->LinkDirectoriesPosition, vec, lfbt);
+             this->Snapshot_.Position->LinkDirectoriesPosition, vec);
 }
 
 void cmStateDirectory::ClearLinkDirectories()
 {
   ClearContent(this->DirectoryState->LinkDirectories,
-               this->DirectoryState->LinkDirectoriesBacktraces,
                this->Snapshot_.Position->LinkDirectoriesPosition);
 }
 
-void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
-                                   cmListFileBacktrace const& lfbt)
+template <typename ValueType>
+void cmStateDirectory::StoreProperty(const std::string& prop, ValueType value,
+                                     cmListFileBacktrace const& lfbt)
 {
   if (prop == "INCLUDE_DIRECTORIES") {
     if (!value) {
       this->ClearIncludeDirectories();
       return;
     }
-    this->SetIncludeDirectories(value, lfbt);
+    this->SetIncludeDirectories(BT<std::string>(value, lfbt));
     return;
   }
   if (prop == "COMPILE_OPTIONS") {
@@ -377,7 +287,7 @@ void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
       this->ClearCompileOptions();
       return;
     }
-    this->SetCompileOptions(value, lfbt);
+    this->SetCompileOptions(BT<std::string>(value, lfbt));
     return;
   }
   if (prop == "COMPILE_DEFINITIONS") {
@@ -385,7 +295,7 @@ void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
       this->ClearCompileDefinitions();
       return;
     }
-    this->SetCompileDefinitions(value, lfbt);
+    this->SetCompileDefinitions(BT<std::string>(value, lfbt));
     return;
   }
   if (prop == "LINK_OPTIONS") {
@@ -393,7 +303,7 @@ void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
       this->ClearLinkOptions();
       return;
     }
-    this->SetLinkOptions(value, lfbt);
+    this->SetLinkOptions(BT<std::string>(value, lfbt));
     return;
   }
   if (prop == "LINK_DIRECTORIES") {
@@ -401,66 +311,78 @@ void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
       this->ClearLinkDirectories();
       return;
     }
-    this->SetLinkDirectories(value, lfbt);
+    this->SetLinkDirectories(BT<std::string>(value, lfbt));
     return;
   }
 
   this->DirectoryState->Properties.SetProperty(prop, value);
 }
 
+void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
+                                   cmListFileBacktrace const& lfbt)
+{
+  this->StoreProperty(prop, value, lfbt);
+}
+void cmStateDirectory::SetProperty(const std::string& prop, cmValue value,
+                                   cmListFileBacktrace const& lfbt)
+{
+  this->StoreProperty(prop, value, lfbt);
+}
+
 void cmStateDirectory::AppendProperty(const std::string& prop,
                                       const std::string& value, bool asString,
                                       cmListFileBacktrace const& lfbt)
 {
   if (prop == "INCLUDE_DIRECTORIES") {
-    this->AppendIncludeDirectoriesEntry(value, lfbt);
+    this->AppendIncludeDirectoriesEntry(BT<std::string>(value, lfbt));
     return;
   }
   if (prop == "COMPILE_OPTIONS") {
-    this->AppendCompileOptionsEntry(value, lfbt);
+    this->AppendCompileOptionsEntry(BT<std::string>(value, lfbt));
     return;
   }
   if (prop == "COMPILE_DEFINITIONS") {
-    this->AppendCompileDefinitionsEntry(value, lfbt);
+    this->AppendCompileDefinitionsEntry(BT<std::string>(value, lfbt));
     return;
   }
   if (prop == "LINK_OPTIONS") {
-    this->AppendLinkOptionsEntry(value, lfbt);
+    this->AppendLinkOptionsEntry(BT<std::string>(value, lfbt));
     return;
   }
   if (prop == "LINK_DIRECTORIES") {
-    this->AppendLinkDirectoriesEntry(value, lfbt);
+    this->AppendLinkDirectoriesEntry(BT<std::string>(value, lfbt));
     return;
   }
 
   this->DirectoryState->Properties.AppendProperty(prop, value, asString);
 }
 
-cmProp cmStateDirectory::GetProperty(const std::string& prop) const
+cmValue cmStateDirectory::GetProperty(const std::string& prop) const
 {
   const bool chain =
     this->Snapshot_.State->IsPropertyChained(prop, cmProperty::DIRECTORY);
   return this->GetProperty(prop, chain);
 }
 
-cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const
+cmValue cmStateDirectory::GetProperty(const std::string& prop,
+                                      bool chain) const
 {
   static std::string output;
   output.clear();
   if (prop == "PARENT_DIRECTORY") {
     cmStateSnapshot parent = this->Snapshot_.GetBuildsystemDirectoryParent();
     if (parent.IsValid()) {
-      return &parent.GetDirectory().GetCurrentSource();
+      return cmValue(parent.GetDirectory().GetCurrentSource());
     }
-    return &output;
+    return cmValue(output);
   }
   if (prop == kBINARY_DIR) {
     output = this->GetCurrentBinary();
-    return &output;
+    return cmValue(output);
   }
   if (prop == kSOURCE_DIR) {
     output = this->GetCurrentSource();
-    return &output;
+    return cmValue(output);
   }
   if (prop == kSUBDIRECTORIES) {
     std::vector<std::string> child_dirs;
@@ -471,15 +393,15 @@ cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const
       child_dirs.push_back(ci.GetDirectory().GetCurrentSource());
     }
     output = cmJoin(child_dirs, ";");
-    return &output;
+    return cmValue(output);
   }
   if (prop == kBUILDSYSTEM_TARGETS) {
     output = cmJoin(this->DirectoryState->NormalTargetNames, ";");
-    return &output;
+    return cmValue(output);
   }
   if (prop == "IMPORTED_TARGETS"_s) {
     output = cmJoin(this->DirectoryState->ImportedTargetNames, ";");
-    return &output;
+    return cmValue(output);
   }
 
   if (prop == "LISTFILE_STACK") {
@@ -491,41 +413,41 @@ cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const
     }
     std::reverse(listFiles.begin(), listFiles.end());
     output = cmJoin(listFiles, ";");
-    return &output;
+    return cmValue(output);
   }
   if (prop == "CACHE_VARIABLES") {
     output = cmJoin(this->Snapshot_.State->GetCacheEntryKeys(), ";");
-    return &output;
+    return cmValue(output);
   }
   if (prop == "VARIABLES") {
     std::vector<std::string> res = this->Snapshot_.ClosureKeys();
     cm::append(res, this->Snapshot_.State->GetCacheEntryKeys());
     std::sort(res.begin(), res.end());
     output = cmJoin(res, ";");
-    return &output;
+    return cmValue(output);
   }
   if (prop == "INCLUDE_DIRECTORIES") {
     output = cmJoin(this->GetIncludeDirectoriesEntries(), ";");
-    return &output;
+    return cmValue(output);
   }
   if (prop == "COMPILE_OPTIONS") {
     output = cmJoin(this->GetCompileOptionsEntries(), ";");
-    return &output;
+    return cmValue(output);
   }
   if (prop == "COMPILE_DEFINITIONS") {
     output = cmJoin(this->GetCompileDefinitionsEntries(), ";");
-    return &output;
+    return cmValue(output);
   }
   if (prop == "LINK_OPTIONS") {
     output = cmJoin(this->GetLinkOptionsEntries(), ";");
-    return &output;
+    return cmValue(output);
   }
   if (prop == "LINK_DIRECTORIES") {
     output = cmJoin(this->GetLinkDirectoriesEntries(), ";");
-    return &output;
+    return cmValue(output);
   }
 
-  cmProp retVal = this->DirectoryState->Properties.GetPropertyValue(prop);
+  cmValue retVal = this->DirectoryState->Properties.GetPropertyValue(prop);
   if (!retVal && chain) {
     cmStateSnapshot parentSnapshot =
       this->Snapshot_.GetBuildsystemDirectoryParent();
index b8abccb..6429f32 100644 (file)
 #include "cmAlgorithms.h"
 #include "cmLinkedTree.h"
 #include "cmListFileCache.h"
-#include "cmProperty.h"
 #include "cmStatePrivate.h"
 #include "cmStateSnapshot.h"
-#include "cmStringAlgorithms.h"
+#include "cmValue.h"
 
 class cmStateDirectory
 {
@@ -28,55 +27,41 @@ public:
   std::string const& GetCurrentBinary() const;
   void SetCurrentBinary(std::string const& dir);
 
-  cmStringRange GetIncludeDirectoriesEntries() const;
-  cmBacktraceRange GetIncludeDirectoriesEntryBacktraces() const;
-  void AppendIncludeDirectoriesEntry(std::string const& vec,
-                                     cmListFileBacktrace const& lfbt);
-  void PrependIncludeDirectoriesEntry(std::string const& vec,
-                                      cmListFileBacktrace const& lfbt);
-  void SetIncludeDirectories(std::string const& vec,
-                             cmListFileBacktrace const& lfbt);
+  cmBTStringRange GetIncludeDirectoriesEntries() const;
+  void AppendIncludeDirectoriesEntry(BT<std::string> const& vec);
+  void PrependIncludeDirectoriesEntry(BT<std::string> const& vec);
+  void SetIncludeDirectories(BT<std::string> const& vec);
   void ClearIncludeDirectories();
 
-  cmStringRange GetCompileDefinitionsEntries() const;
-  cmBacktraceRange GetCompileDefinitionsEntryBacktraces() const;
-  void AppendCompileDefinitionsEntry(std::string const& vec,
-                                     cmListFileBacktrace const& lfbt);
-  void SetCompileDefinitions(std::string const& vec,
-                             cmListFileBacktrace const& lfbt);
+  cmBTStringRange GetCompileDefinitionsEntries() const;
+  void AppendCompileDefinitionsEntry(BT<std::string> const& vec);
+  void SetCompileDefinitions(BT<std::string> const& vec);
   void ClearCompileDefinitions();
 
-  cmStringRange GetCompileOptionsEntries() const;
-  cmBacktraceRange GetCompileOptionsEntryBacktraces() const;
-  void AppendCompileOptionsEntry(std::string const& vec,
-                                 cmListFileBacktrace const& lfbt);
-  void SetCompileOptions(std::string const& vec,
-                         cmListFileBacktrace const& lfbt);
+  cmBTStringRange GetCompileOptionsEntries() const;
+  void AppendCompileOptionsEntry(BT<std::string> const& vec);
+  void SetCompileOptions(BT<std::string> const& vec);
   void ClearCompileOptions();
 
-  cmStringRange GetLinkOptionsEntries() const;
-  cmBacktraceRange GetLinkOptionsEntryBacktraces() const;
-  void AppendLinkOptionsEntry(std::string const& vec,
-                              cmListFileBacktrace const& lfbt);
-  void PrependLinkDirectoriesEntry(std::string const& vec,
-                                   cmListFileBacktrace const& lfbt);
-  void SetLinkOptions(std::string const& vec, cmListFileBacktrace const& lfbt);
+  cmBTStringRange GetLinkOptionsEntries() const;
+  void AppendLinkOptionsEntry(BT<std::string> const& vec);
+  void PrependLinkDirectoriesEntry(BT<std::string> const& vec);
+  void SetLinkOptions(BT<std::string> const& vec);
   void ClearLinkOptions();
 
-  cmStringRange GetLinkDirectoriesEntries() const;
-  cmBacktraceRange GetLinkDirectoriesEntryBacktraces() const;
-  void AppendLinkDirectoriesEntry(std::string const& vec,
-                                  cmListFileBacktrace const& lfbt);
-  void SetLinkDirectories(std::string const& vec,
-                          cmListFileBacktrace const& lfbt);
+  cmBTStringRange GetLinkDirectoriesEntries() const;
+  void AppendLinkDirectoriesEntry(BT<std::string> const& vec);
+  void SetLinkDirectories(BT<std::string> const& vecs);
   void ClearLinkDirectories();
 
   void SetProperty(const std::string& prop, const char* value,
                    cmListFileBacktrace const& lfbt);
+  void SetProperty(const std::string& prop, cmValue value,
+                   cmListFileBacktrace const& lfbt);
   void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString, cmListFileBacktrace const& lfbt);
-  cmProp GetProperty(const std::string& prop) const;
-  cmProp GetProperty(const std::string& prop, bool chain) const;
+  cmValue GetProperty(const std::string& prop) const;
+  cmValue GetProperty(const std::string& prop, bool chain) const;
   bool GetPropertyAsBool(const std::string& prop) const;
   std::vector<std::string> GetPropertyKeys() const;
 
@@ -84,6 +69,10 @@ public:
   void AddImportedTargetName(std::string const& name);
 
 private:
+  template <typename ValueType>
+  void StoreProperty(const std::string& prop, ValueType value,
+                     cmListFileBacktrace const& lfbt);
+
   cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>::iterator
     DirectoryState;
   cmStateSnapshot Snapshot_;
index 6f475f2..fd46eed 100644 (file)
@@ -67,20 +67,15 @@ struct cmStateDetail::BuildsystemDirectoryStateType
   std::string Location;
   std::string OutputLocation;
 
-  std::vector<std::string> IncludeDirectories;
-  std::vector<cmListFileBacktrace> IncludeDirectoryBacktraces;
+  std::vector<BT<std::string>> IncludeDirectories;
 
-  std::vector<std::string> CompileDefinitions;
-  std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces;
+  std::vector<BT<std::string>> CompileDefinitions;
 
-  std::vector<std::string> CompileOptions;
-  std::vector<cmListFileBacktrace> CompileOptionsBacktraces;
+  std::vector<BT<std::string>> CompileOptions;
 
-  std::vector<std::string> LinkOptions;
-  std::vector<cmListFileBacktrace> LinkOptionsBacktraces;
+  std::vector<BT<std::string>> LinkOptions;
 
-  std::vector<std::string> LinkDirectories;
-  std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
+  std::vector<BT<std::string>> LinkDirectories;
 
   std::vector<std::string> NormalTargetNames;
   std::vector<std::string> ImportedTargetNames;
index fbf47ef..f73df8f 100644 (file)
 
 #include "cmDefinitions.h"
 #include "cmListFileCache.h"
-#include "cmProperty.h"
 #include "cmPropertyMap.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStatePrivate.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmVersion.h"
 
+#if defined(__CYGWIN__)
+#  include "cmStringAlgorithms.h"
+#endif
+
 cmStateSnapshot::cmStateSnapshot(cmState* state)
   : State(state)
 {
@@ -201,8 +205,7 @@ bool cmStateSnapshot::HasDefinedPolicyCMP0011()
   return !this->Position->Policies->IsEmpty();
 }
 
-std::string const* cmStateSnapshot::GetDefinition(
-  std::string const& name) const
+cmValue cmStateSnapshot::GetDefinition(std::string const& name) const
 {
   assert(this->Position->Vars.IsValid());
   return cmDefinitions::Get(name, this->Position->Vars, this->Position->Root);
@@ -260,12 +263,10 @@ bool cmStateSnapshot::RaiseScope(std::string const& var, const char* varDef)
   return true;
 }
 
-template <typename T, typename U, typename V>
+template <typename T, typename U>
 void InitializeContentFromParent(T& parentContent, T& thisContent,
-                                 U& parentBacktraces, U& thisBacktraces,
-                                 V& contentEndPosition)
+                                 U& contentEndPosition)
 {
-  auto parentBegin = parentContent.begin();
   auto parentEnd = parentContent.end();
 
   auto parentRbegin = cm::make_reverse_iterator(parentEnd);
@@ -273,12 +274,7 @@ void InitializeContentFromParent(T& parentContent, T& thisContent,
   parentRbegin = std::find(parentRbegin, parentRend, cmPropertySentinal);
   auto parentIt = parentRbegin.base();
 
-  thisContent = std::vector<std::string>(parentIt, parentEnd);
-
-  auto btIt = parentBacktraces.begin() + std::distance(parentBegin, parentIt);
-  auto btEnd = parentBacktraces.end();
-
-  thisBacktraces = std::vector<cmListFileBacktrace>(btIt, btEnd);
+  thisContent = std::vector<BT<std::string>>(parentIt, parentEnd);
 
   contentEndPosition = thisContent.size();
 }
@@ -360,43 +356,33 @@ void cmStateSnapshot::InitializeFromParent()
   InitializeContentFromParent(
     parent->BuildSystemDirectory->IncludeDirectories,
     this->Position->BuildSystemDirectory->IncludeDirectories,
-    parent->BuildSystemDirectory->IncludeDirectoryBacktraces,
-    this->Position->BuildSystemDirectory->IncludeDirectoryBacktraces,
     this->Position->IncludeDirectoryPosition);
 
   InitializeContentFromParent(
     parent->BuildSystemDirectory->CompileDefinitions,
     this->Position->BuildSystemDirectory->CompileDefinitions,
-    parent->BuildSystemDirectory->CompileDefinitionsBacktraces,
-    this->Position->BuildSystemDirectory->CompileDefinitionsBacktraces,
     this->Position->CompileDefinitionsPosition);
 
   InitializeContentFromParent(
     parent->BuildSystemDirectory->CompileOptions,
     this->Position->BuildSystemDirectory->CompileOptions,
-    parent->BuildSystemDirectory->CompileOptionsBacktraces,
-    this->Position->BuildSystemDirectory->CompileOptionsBacktraces,
     this->Position->CompileOptionsPosition);
 
   InitializeContentFromParent(
     parent->BuildSystemDirectory->LinkOptions,
     this->Position->BuildSystemDirectory->LinkOptions,
-    parent->BuildSystemDirectory->LinkOptionsBacktraces,
-    this->Position->BuildSystemDirectory->LinkOptionsBacktraces,
     this->Position->LinkOptionsPosition);
 
   InitializeContentFromParent(
     parent->BuildSystemDirectory->LinkDirectories,
     this->Position->BuildSystemDirectory->LinkDirectories,
-    parent->BuildSystemDirectory->LinkDirectoriesBacktraces,
-    this->Position->BuildSystemDirectory->LinkDirectoriesBacktraces,
     this->Position->LinkDirectoriesPosition);
 
-  cmProp include_regex =
+  cmValue include_regex =
     parent->BuildSystemDirectory->Properties.GetPropertyValue(
       "INCLUDE_REGULAR_EXPRESSION");
   this->Position->BuildSystemDirectory->Properties.SetProperty(
-    "INCLUDE_REGULAR_EXPRESSION", cmToCStr(include_regex));
+    "INCLUDE_REGULAR_EXPRESSION", include_regex);
 }
 
 cmState* cmStateSnapshot::GetState() const
index d06cba3..a61ec83 100644 (file)
@@ -13,6 +13,7 @@
 #include "cmLinkedTree.h"
 #include "cmPolicies.h"
 #include "cmStateTypes.h"
+#include "cmValue.h"
 
 class cmState;
 class cmStateDirectory;
@@ -23,7 +24,7 @@ public:
   cmStateSnapshot(cmState* state = nullptr);
   cmStateSnapshot(cmState* state, cmStateDetail::PositionType position);
 
-  std::string const* GetDefinition(std::string const& name) const;
+  cmValue GetDefinition(std::string const& name) const;
   bool IsInitialized(std::string const& name) const;
   void SetDefinition(std::string const& name, cm::string_view value);
   void RemoveDefinition(std::string const& name);
index 5bb6e7b..1bb6808 100644 (file)
@@ -218,85 +218,6 @@ std::string cmCatViews(std::initializer_list<cm::string_view> views)
   return result;
 }
 
-bool cmIsInternallyOn(cm::string_view val)
-{
-  return (val.size() == 4) &&           //
-    (val[0] == 'I' || val[0] == 'i') && //
-    (val[1] == '_') &&                  //
-    (val[2] == 'O' || val[2] == 'o') && //
-    (val[3] == 'N' || val[3] == 'n');
-}
-
-bool cmIsNOTFOUND(cm::string_view val)
-{
-  return (val == "NOTFOUND") || cmHasLiteralSuffix(val, "-NOTFOUND");
-}
-
-bool cmIsOn(cm::string_view val)
-{
-  switch (val.size()) {
-    case 1:
-      return val[0] == '1' || val[0] == 'Y' || val[0] == 'y';
-    case 2:
-      return                                //
-        (val[0] == 'O' || val[0] == 'o') && //
-        (val[1] == 'N' || val[1] == 'n');
-    case 3:
-      return                                //
-        (val[0] == 'Y' || val[0] == 'y') && //
-        (val[1] == 'E' || val[1] == 'e') && //
-        (val[2] == 'S' || val[2] == 's');
-    case 4:
-      return                                //
-        (val[0] == 'T' || val[0] == 't') && //
-        (val[1] == 'R' || val[1] == 'r') && //
-        (val[2] == 'U' || val[2] == 'u') && //
-        (val[3] == 'E' || val[3] == 'e');
-    default:
-      break;
-  }
-
-  return false;
-}
-
-bool cmIsOff(cm::string_view val)
-{
-  switch (val.size()) {
-    case 0:
-      return true;
-    case 1:
-      return val[0] == '0' || val[0] == 'N' || val[0] == 'n';
-    case 2:
-      return                                //
-        (val[0] == 'N' || val[0] == 'n') && //
-        (val[1] == 'O' || val[1] == 'o');
-    case 3:
-      return                                //
-        (val[0] == 'O' || val[0] == 'o') && //
-        (val[1] == 'F' || val[1] == 'f') && //
-        (val[2] == 'F' || val[2] == 'f');
-    case 5:
-      return                                //
-        (val[0] == 'F' || val[0] == 'f') && //
-        (val[1] == 'A' || val[1] == 'a') && //
-        (val[2] == 'L' || val[2] == 'l') && //
-        (val[3] == 'S' || val[3] == 's') && //
-        (val[4] == 'E' || val[4] == 'e');
-    case 6:
-      return                                //
-        (val[0] == 'I' || val[0] == 'i') && //
-        (val[1] == 'G' || val[1] == 'g') && //
-        (val[2] == 'N' || val[2] == 'n') && //
-        (val[3] == 'O' || val[3] == 'o') && //
-        (val[4] == 'R' || val[4] == 'r') && //
-        (val[5] == 'E' || val[5] == 'e');
-    default:
-      break;
-  }
-
-  return cmIsNOTFOUND(val);
-}
-
 bool cmStrToLong(const char* str, long* value)
 {
   errno = 0;
index 6b458ec..492e588 100644 (file)
 #include <cm/string_view>
 
 #include "cmRange.h"
+#include "cmValue.h"
 
 /** String range type.  */
 using cmStringRange = cmRange<std::vector<std::string>::const_iterator>;
 
-/** Check for non-empty string.  */
-inline bool cmNonempty(const char* str)
-{
-  return str && *str;
-}
-inline bool cmNonempty(cm::string_view str)
-{
-  return !str.empty();
-}
-inline bool cmNonempty(std::string const* str)
-{
-  return str && !str->empty();
-}
-
 /** Returns length of a literal string.  */
 template <size_t N>
 constexpr size_t cmStrLen(const char (&/*str*/)[N])
@@ -107,6 +94,13 @@ std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep);
  */
 void cmExpandList(cm::string_view arg, std::vector<std::string>& argsOut,
                   bool emptyArgs = false);
+inline void cmExpandList(cmValue arg, std::vector<std::string>& argsOut,
+                         bool emptyArgs = false)
+{
+  if (arg) {
+    cmExpandList(*arg, argsOut, emptyArgs);
+  }
+}
 
 /**
  * Expand out any arguments in the string range [@a first, @a last) that have
@@ -128,6 +122,14 @@ void cmExpandLists(InputIt first, InputIt last,
  */
 std::vector<std::string> cmExpandedList(cm::string_view arg,
                                         bool emptyArgs = false);
+inline std::vector<std::string> cmExpandedList(cmValue arg,
+                                               bool emptyArgs = false)
+{
+  if (!arg) {
+    return {};
+  }
+  return cmExpandedList(*arg, emptyArgs);
+}
 
 /**
  * Same as cmExpandList but a new vector is created containing the expanded
@@ -175,6 +177,10 @@ public:
   cmAlphaNum(unsigned long long int val);
   cmAlphaNum(float val);
   cmAlphaNum(double val);
+  cmAlphaNum(cmValue value)
+    : View_(*value)
+  {
+  }
 
   cm::string_view View() const { return this->View_; }
 
@@ -213,53 +219,6 @@ std::string cmWrap(char prefix, Range const& rng, char suffix,
                 sep);
 }
 
-/**
- * Does a string indicates that CMake/CPack/CTest internally
- * forced this value. This is not the same as On, but this
- * may be considered as "internally switched on".
- */
-bool cmIsInternallyOn(cm::string_view val);
-inline bool cmIsInternallyOn(const char* val)
-{
-  if (!val) {
-    return false;
-  }
-  return cmIsInternallyOn(cm::string_view(val));
-}
-
-/** Return true if value is NOTFOUND or ends in -NOTFOUND.  */
-bool cmIsNOTFOUND(cm::string_view val);
-
-/**
- * Does a string indicate a true or ON value? This is not the same as ifdef.
- */
-bool cmIsOn(cm::string_view val);
-inline bool cmIsOn(const char* val)
-{
-  return val && cmIsOn(cm::string_view(val));
-}
-inline bool cmIsOn(std::string const* val)
-{
-  return val && cmIsOn(*val);
-}
-
-/**
- * Does a string indicate a false or off value ? Note that this is
- * not the same as !IsOn(...) because there are a number of
- * ambiguous values such as "/usr/local/bin" a path will result in
- * IsON and IsOff both returning false. Note that the special path
- * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true.
- */
-bool cmIsOff(cm::string_view val);
-inline bool cmIsOff(const char* val)
-{
-  return !val || cmIsOff(cm::string_view(val));
-}
-inline bool cmIsOff(std::string const* val)
-{
-  return !val || cmIsOff(*val);
-}
-
 /** Returns true if string @a str starts with the character @a prefix.  */
 inline bool cmHasPrefix(cm::string_view str, char prefix)
 {
@@ -273,6 +232,16 @@ inline bool cmHasPrefix(cm::string_view str, cm::string_view prefix)
 }
 
 /** Returns true if string @a str starts with string @a prefix.  */
+inline bool cmHasPrefix(cm::string_view str, cmValue prefix)
+{
+  if (!prefix) {
+    return false;
+  }
+
+  return str.compare(0, prefix->size(), *prefix) == 0;
+}
+
+/** Returns true if string @a str starts with string @a prefix.  */
 template <size_t N>
 inline bool cmHasLiteralPrefix(cm::string_view str, const char (&prefix)[N])
 {
@@ -293,6 +262,17 @@ inline bool cmHasSuffix(cm::string_view str, cm::string_view suffix)
 }
 
 /** Returns true if string @a str ends with string @a suffix.  */
+inline bool cmHasSuffix(cm::string_view str, cmValue suffix)
+{
+  if (!suffix) {
+    return false;
+  }
+
+  return str.size() >= suffix->size() &&
+    str.compare(str.size() - suffix->size(), suffix->size(), *suffix) == 0;
+}
+
+/** Returns true if string @a str ends with string @a suffix.  */
 template <size_t N>
 inline bool cmHasLiteralSuffix(cm::string_view str, const char (&suffix)[N])
 {
index 5fa309d..f44fcf7 100644 (file)
@@ -31,7 +31,6 @@
 #include "cmGeneratorExpression.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmStringReplaceHelper.h"
@@ -39,6 +38,7 @@
 #include "cmSystemTools.h"
 #include "cmTimestamp.h"
 #include "cmUuid.h"
+#include "cmValue.h"
 
 namespace {
 
@@ -572,7 +572,7 @@ bool HandlePrependCommand(std::vector<std::string> const& args,
   const std::string& variable = args[1];
 
   std::string value = cmJoin(cmMakeRange(args).advance(2), std::string());
-  cmProp oldValue = status.GetMakefile().GetDefinition(variable);
+  cmValue oldValue = status.GetMakefile().GetDefinition(variable);
   if (oldValue) {
     value += *oldValue;
   }
@@ -1054,7 +1054,7 @@ Json::Value& ResolvePath(Json::Value& json, Args path)
     }
   }
   return *search;
-};
+}
 
 Json::Value ReadJson(const std::string& jsonstr)
 {
index 10d2e50..75a5a8d 100644 (file)
 #include <cm3p/uv.h>
 
 #include "cmDuration.h"
+#include "cmELF.h"
 #include "cmMessageMetadata.h"
 #include "cmProcessOutput.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
+#include "cmValue.h"
 
 #if !defined(CMAKE_BOOTSTRAP)
 #  include <cm3p/archive.h>
 #  include "cmCryptoHash.h"
 #endif
 
-#if defined(CMake_USE_ELF_PARSER)
-#  include "cmELF.h"
-#endif
-
 #if defined(CMake_USE_MACH_PARSER)
 #  include "cmMachO.h"
 #endif
@@ -1595,6 +1593,12 @@ bool cmSystemTools::IsPathToFramework(const std::string& path)
           cmHasLiteralSuffix(path, ".framework"));
 }
 
+bool cmSystemTools::IsPathToMacOSSharedLibrary(const std::string& path)
+{
+  return (cmSystemTools::FileIsFullPath(path) &&
+          cmHasLiteralSuffix(path, ".dylib"));
+}
+
 bool cmSystemTools::CreateTar(const std::string& outFileName,
                               const std::vector<std::string>& files,
                               cmTarCompression compressType, bool verbose,
@@ -1632,7 +1636,10 @@ bool cmSystemTools::CreateTar(const std::string& outFileName,
   cmArchiveWrite a(fout, compress, format.empty() ? "paxr" : format,
                    compressionLevel);
 
-  a.Open();
+  if (!a.Open()) {
+    cmSystemTools::Error(a.GetError());
+    return false;
+  }
   a.SetMTime(mtime);
   a.SetVerbose(verbose);
   bool tarCreatedSuccessfully = true;
@@ -2446,14 +2453,12 @@ void cmSystemTools::MakefileColorEcho(int color, const char* message,
 bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath,
                                        std::string& soname)
 {
-// For ELF shared libraries use a real parser to get the correct
-// soname.
-#if defined(CMake_USE_ELF_PARSER)
+  // For ELF shared libraries use a real parser to get the correct
+  // soname.
   cmELF elf(fullPath.c_str());
   if (elf) {
     return elf.GetSOName(soname);
   }
-#endif
 
   // If the file is not a symlink we have no guess for its soname.
   if (!cmSystemTools::FileIsSymlink(fullPath)) {
@@ -2491,7 +2496,6 @@ bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath,
   return false;
 }
 
-#if defined(CMake_USE_ELF_PARSER) || defined(CMake_USE_XCOFF_PARSER)
 std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have,
                                               cm::string_view const& want)
 {
@@ -2523,9 +2527,7 @@ std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have,
   // The desired rpath was not found.
   return std::string::npos;
 }
-#endif
 
-#if defined(CMake_USE_ELF_PARSER)
 namespace {
 struct cmSystemToolsRPathInfo
 {
@@ -2539,10 +2541,10 @@ using EmptyCallback = std::function<bool(std::string*, const cmELF&)>;
 using AdjustCallback = std::function<bool(
   cm::optional<std::string>&, const std::string&, const char*, std::string*)>;
 
-// FIXME: Dispatch if multiple formats are supported.
-bool AdjustRPath(std::string const& file, const EmptyCallback& emptyCallback,
-                 const AdjustCallback& adjustCallback, std::string* emsg,
-                 bool* changed)
+cm::optional<bool> AdjustRPathELF(std::string const& file,
+                                  const EmptyCallback& emptyCallback,
+                                  const AdjustCallback& adjustCallback,
+                                  std::string* emsg, bool* changed)
 {
   if (changed) {
     *changed = false;
@@ -2553,6 +2555,9 @@ bool AdjustRPath(std::string const& file, const EmptyCallback& emptyCallback,
   {
     // Parse the ELF binary.
     cmELF elf(file.c_str());
+    if (!elf) {
+      return cm::nullopt; // Not a valid ELF file.
+    }
 
     // Get the RPATH and RUNPATH entries from it.
     int se_count = 0;
@@ -2686,14 +2691,14 @@ std::function<bool(std::string*, const cmELF&)> MakeEmptyCallback(
     }
     return false;
   };
-};
+}
 }
 
-bool cmSystemTools::ChangeRPath(std::string const& file,
-                                std::string const& oldRPath,
-                                std::string const& newRPath,
-                                bool removeEnvironmentRPath, std::string* emsg,
-                                bool* changed)
+cm::optional<bool> ChangeRPathELF(std::string const& file,
+                                  std::string const& oldRPath,
+                                  std::string const& newRPath,
+                                  bool removeEnvironmentRPath,
+                                  std::string* emsg, bool* changed)
 {
   auto adjustCallback = [oldRPath, newRPath, removeEnvironmentRPath](
                           cm::optional<std::string>& outRPath,
@@ -2741,13 +2746,13 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
     return true;
   };
 
-  return AdjustRPath(file, MakeEmptyCallback(newRPath), adjustCallback, emsg,
-                     changed);
+  return AdjustRPathELF(file, MakeEmptyCallback(newRPath), adjustCallback,
+                        emsg, changed);
 }
 
-bool cmSystemTools::SetRPath(std::string const& file,
-                             std::string const& newRPath, std::string* emsg,
-                             bool* changed)
+static cm::optional<bool> SetRPathELF(std::string const& file,
+                                      std::string const& newRPath,
+                                      std::string* emsg, bool* changed)
 {
   auto adjustCallback = [newRPath](cm::optional<std::string>& outRPath,
                                    const std::string& inRPath,
@@ -2759,22 +2764,31 @@ bool cmSystemTools::SetRPath(std::string const& file,
     return true;
   };
 
-  return AdjustRPath(file, MakeEmptyCallback(newRPath), adjustCallback, emsg,
-                     changed);
+  return AdjustRPathELF(file, MakeEmptyCallback(newRPath), adjustCallback,
+                        emsg, changed);
 }
-#elif defined(CMake_USE_XCOFF_PARSER)
-bool cmSystemTools::ChangeRPath(std::string const& file,
-                                std::string const& oldRPath,
-                                std::string const& newRPath,
-                                bool removeEnvironmentRPath, std::string* emsg,
-                                bool* changed)
+static cm::optional<bool> ChangeRPathXCOFF(std::string const& file,
+                                           std::string const& oldRPath,
+                                           std::string const& newRPath,
+                                           bool removeEnvironmentRPath,
+                                           std::string* emsg, bool* changed)
 {
   if (changed) {
     *changed = false;
   }
-
+#if !defined(CMake_USE_XCOFF_PARSER)
+  (void)file;
+  (void)oldRPath;
+  (void)newRPath;
+  (void)removeEnvironmentRPath;
+  (void)emsg;
+  return cm::nullopt;
+#else
   bool chg = false;
   cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite);
+  if (!xcoff) {
+    return cm::nullopt; // Not a valid XCOFF file
+  }
   if (cm::optional<cm::string_view> maybeLibPath = xcoff.GetLibPath()) {
     cm::string_view libPath = *maybeLibPath;
     // Make sure the current rpath contains the old rpath.
@@ -2830,34 +2844,51 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
     *changed = chg;
   }
   return true;
+#endif
 }
 
-bool cmSystemTools::SetRPath(std::string const& /*file*/,
-                             std::string const& /*newRPath*/,
-                             std::string* /*emsg*/, bool* /*changed*/)
+static cm::optional<bool> SetRPathXCOFF(std::string const& /*file*/,
+                                        std::string const& /*newRPath*/,
+                                        std::string* /*emsg*/,
+                                        bool* /*changed*/)
 {
-  return false;
+  return cm::nullopt; // Not implemented.
 }
-#else
-bool cmSystemTools::ChangeRPath(std::string const& /*file*/,
-                                std::string const& /*oldRPath*/,
-                                std::string const& /*newRPath*/,
-                                bool /*removeEnvironmentRPath*/,
-                                std::string* /*emsg*/, bool* /*changed*/)
+
+bool cmSystemTools::ChangeRPath(std::string const& file,
+                                std::string const& oldRPath,
+                                std::string const& newRPath,
+                                bool removeEnvironmentRPath, std::string* emsg,
+                                bool* changed)
 {
+  if (cm::optional<bool> result = ChangeRPathELF(
+        file, oldRPath, newRPath, removeEnvironmentRPath, emsg, changed)) {
+    return result.value();
+  }
+  if (cm::optional<bool> result = ChangeRPathXCOFF(
+        file, oldRPath, newRPath, removeEnvironmentRPath, emsg, changed)) {
+    return result.value();
+  }
   return false;
 }
 
-bool cmSystemTools::SetRPath(std::string const& /*file*/,
-                             std::string const& /*newRPath*/,
-                             std::string* /*emsg*/, bool* /*changed*/)
+bool cmSystemTools::SetRPath(std::string const& file,
+                             std::string const& newRPath, std::string* emsg,
+                             bool* changed)
 {
+  if (cm::optional<bool> result = SetRPathELF(file, newRPath, emsg, changed)) {
+    return result.value();
+  }
+  if (cm::optional<bool> result =
+        SetRPathXCOFF(file, newRPath, emsg, changed)) {
+    return result.value();
+  }
   return false;
 }
-#endif
 
-bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op,
-                                   const char* lhss, const char* rhss)
+namespace {
+bool VersionCompare(cmSystemTools::CompareOp op, const char* lhss,
+                    const char* rhss)
 {
   const char* endl = lhss;
   const char* endr = rhss;
@@ -2890,26 +2921,37 @@ bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op,
   // lhs == rhs, so true if operation is EQUAL
   return (op & cmSystemTools::OP_EQUAL) != 0;
 }
+}
+
+bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op,
+                                   const std::string& lhs,
+                                   const std::string& rhs)
+{
+  return ::VersionCompare(op, lhs.c_str(), rhs.c_str());
+}
+bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op,
+                                   const std::string& lhs, const char rhs[])
+{
+  return ::VersionCompare(op, lhs.c_str(), rhs);
+}
 
 bool cmSystemTools::VersionCompareEqual(std::string const& lhs,
                                         std::string const& rhs)
 {
-  return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, lhs.c_str(),
-                                       rhs.c_str());
+  return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, lhs, rhs);
 }
 
 bool cmSystemTools::VersionCompareGreater(std::string const& lhs,
                                           std::string const& rhs)
 {
-  return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, lhs.c_str(),
-                                       rhs.c_str());
+  return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, lhs, rhs);
 }
 
 bool cmSystemTools::VersionCompareGreaterEq(std::string const& lhs,
                                             std::string const& rhs)
 {
-  return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
-                                       lhs.c_str(), rhs.c_str());
+  return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, lhs,
+                                       rhs);
 }
 
 static size_t cm_strverscmp_find_first_difference_or_end(const char* lhs,
@@ -2989,10 +3031,8 @@ int cmSystemTools::strverscmp(std::string const& lhs, std::string const& rhs)
   return cm_strverscmp(lhs.c_str(), rhs.c_str());
 }
 
-// FIXME: Dispatch if multiple formats are supported.
-#if defined(CMake_USE_ELF_PARSER)
-bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
-                                bool* removed)
+static cm::optional<bool> RemoveRPathELF(std::string const& file,
+                                         std::string* emsg, bool* removed)
 {
   if (removed) {
     *removed = false;
@@ -3005,6 +3045,9 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
   {
     // Parse the ELF binary.
     cmELF elf(file.c_str());
+    if (!elf) {
+      return cm::nullopt; // Not a valid ELF file.
+    }
 
     // Get the RPATH and RUNPATH entries from it and sort them by index
     // in the dynamic section header.
@@ -3054,8 +3097,7 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
         entriesErased++;
         continue;
       }
-      if (cmELF::TagMipsRldMapRel != 0 &&
-          it->first == cmELF::TagMipsRldMapRel) {
+      if (it->first == cmELF::TagMipsRldMapRel && elf.IsMIPS()) {
         // Background: debuggers need to know the "linker map" which contains
         // the addresses each dynamic object is loaded at. Most arches use
         // the DT_DEBUG tag which the dynamic linker writes to (directly) and
@@ -3131,15 +3173,22 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
   }
   return true;
 }
-#elif defined(CMake_USE_XCOFF_PARSER)
-bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
-                                bool* removed)
+
+static cm::optional<bool> RemoveRPathXCOFF(std::string const& file,
+                                           std::string* emsg, bool* removed)
 {
   if (removed) {
     *removed = false;
   }
-
+#if !defined(CMake_USE_XCOFF_PARSER)
+  (void)file;
+  (void)emsg;
+  return cm::nullopt; // Cannot handle XCOFF files.
+#else
   cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite);
+  if (!xcoff) {
+    return cm::nullopt; // Not a valid XCOFF file.
+  }
   bool rm = xcoff.RemoveLibPath();
   if (!xcoff) {
     if (emsg) {
@@ -3152,55 +3201,60 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
     *removed = rm;
   }
   return true;
+#endif
 }
-#else
-bool cmSystemTools::RemoveRPath(std::string const& /*file*/,
-                                std::string* /*emsg*/, bool* /*removed*/)
+bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
+                                bool* removed)
 {
+  if (cm::optional<bool> result = RemoveRPathELF(file, emsg, removed)) {
+    return result.value();
+  }
+  if (cm::optional<bool> result = RemoveRPathXCOFF(file, emsg, removed)) {
+    return result.value();
+  }
   return false;
 }
-#endif
 
-// FIXME: Dispatch if multiple formats are supported.
 bool cmSystemTools::CheckRPath(std::string const& file,
                                std::string const& newRPath)
 {
-#if defined(CMake_USE_ELF_PARSER)
   // Parse the ELF binary.
   cmELF elf(file.c_str());
-
-  // Get the RPATH or RUNPATH entry from it.
-  cmELF::StringEntry const* se = elf.GetRPath();
-  if (!se) {
-    se = elf.GetRunPath();
-  }
-
-  // Make sure the current rpath contains the new rpath.
-  if (newRPath.empty()) {
+  if (elf) {
+    // Get the RPATH or RUNPATH entry from it.
+    cmELF::StringEntry const* se = elf.GetRPath();
     if (!se) {
-      return true;
+      se = elf.GetRunPath();
     }
-  } else {
-    if (se &&
-        cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) {
-      return true;
+
+    // Make sure the current rpath contains the new rpath.
+    if (newRPath.empty()) {
+      if (!se) {
+        return true;
+      }
+    } else {
+      if (se &&
+          cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) {
+        return true;
+      }
     }
+    return false;
   }
-  return false;
-#elif defined(CMake_USE_XCOFF_PARSER)
+#if defined(CMake_USE_XCOFF_PARSER)
   // Parse the XCOFF binary.
   cmXCOFF xcoff(file.c_str());
-  if (cm::optional<cm::string_view> libPath = xcoff.GetLibPath()) {
-    if (cmSystemToolsFindRPath(*libPath, newRPath) != std::string::npos) {
-      return true;
+  if (xcoff) {
+    if (cm::optional<cm::string_view> libPath = xcoff.GetLibPath()) {
+      if (cmSystemToolsFindRPath(*libPath, newRPath) != std::string::npos) {
+        return true;
+      }
     }
+    return false;
   }
-  return false;
-#else
+#endif
   (void)file;
   (void)newRPath;
   return false;
-#endif
 }
 
 bool cmSystemTools::RepeatedRemoveDirectory(const std::string& dir)
index 44ccbf7..715724c 100644 (file)
@@ -102,7 +102,11 @@ public:
   }
 
   //! Return true if the path is a framework
-  static bool IsPathToFramework(const std::string& value);
+  static bool IsPathToFramework(const std::string& path);
+
+  //! Return true if the path is a macOS non-framework shared library (aka
+  //! .dylib)
+  static bool IsPathToMacOSSharedLibrary(const std::string& path);
 
   static bool DoesFileExistWithExtensions(
     const std::string& name, const std::vector<std::string>& sourceExts);
@@ -280,7 +284,10 @@ public:
   /**
    * Compare versions
    */
-  static bool VersionCompare(CompareOp op, const char* lhs, const char* rhs);
+  static bool VersionCompare(CompareOp op, const std::string& lhs,
+                             const std::string& rhs);
+  static bool VersionCompare(CompareOp op, const std::string& lhs,
+                             const char rhs[]);
   static bool VersionCompareEqual(std::string const& lhs,
                                   std::string const& rhs);
   static bool VersionCompareGreater(std::string const& lhs,
index 7622700..97d60cf 100644 (file)
@@ -37,6 +37,7 @@
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
 #include "cmTargetPropertyComputer.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 template <>
@@ -79,19 +80,19 @@ const std::string& cmTargetPropertyComputer::ComputeLocation<cmTarget>(
 }
 
 template <>
-cmProp cmTargetPropertyComputer::GetSources<cmTarget>(
+cmValue cmTargetPropertyComputer::GetSources<cmTarget>(
   cmTarget const* tgt, cmMessenger* messenger,
   cmListFileBacktrace const& context)
 {
-  cmStringRange entries = tgt->GetSourceEntries();
+  cmBTStringRange entries = tgt->GetSourceEntries();
   if (entries.empty()) {
     return nullptr;
   }
 
   std::ostringstream ss;
   const char* sep = "";
-  for (std::string const& entry : entries) {
-    std::vector<std::string> files = cmExpandedList(entry);
+  for (auto const& entry : entries) {
+    std::vector<std::string> files = cmExpandedList(entry.Value);
     for (std::string const& file : files) {
       if (cmHasLiteralPrefix(file, "$<TARGET_OBJECTS:") &&
           file.back() == '>') {
@@ -112,12 +113,14 @@ cmProp cmTargetPropertyComputer::GetSources<cmTarget>(
           case cmPolicies::WARN:
             e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0051) << "\n";
             noMessage = false;
+            CM_FALLTHROUGH;
           case cmPolicies::OLD:
             break;
           case cmPolicies::REQUIRED_ALWAYS:
           case cmPolicies::REQUIRED_IF_USED:
           case cmPolicies::NEW:
             addContent = true;
+            break;
         }
         if (!noMessage) {
           e << "Target \"" << tgt->GetName()
@@ -157,7 +160,7 @@ cmProp cmTargetPropertyComputer::GetSources<cmTarget>(
   }
   static std::string srcs;
   srcs = ss.str();
-  return &srcs;
+  return cmValue(srcs);
 }
 
 class cmTargetInternals
@@ -187,24 +190,16 @@ public:
   std::set<std::string> SystemIncludeDirectories;
   cmTarget::LinkLibraryVectorType OriginalLinkLibraries;
   std::map<std::string, BTs<std::string>> LanguageStandardProperties;
-  std::vector<std::string> IncludeDirectoriesEntries;
-  std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces;
-  std::vector<std::string> CompileOptionsEntries;
-  std::vector<cmListFileBacktrace> CompileOptionsBacktraces;
-  std::vector<std::string> CompileFeaturesEntries;
-  std::vector<cmListFileBacktrace> CompileFeaturesBacktraces;
-  std::vector<std::string> CompileDefinitionsEntries;
-  std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces;
-  std::vector<std::string> PrecompileHeadersEntries;
-  std::vector<cmListFileBacktrace> PrecompileHeadersBacktraces;
-  std::vector<std::string> SourceEntries;
-  std::vector<cmListFileBacktrace> SourceBacktraces;
-  std::vector<std::string> LinkOptionsEntries;
-  std::vector<cmListFileBacktrace> LinkOptionsBacktraces;
-  std::vector<std::string> LinkDirectoriesEntries;
-  std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
-  std::vector<std::string> LinkImplementationPropertyEntries;
-  std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces;
+  std::vector<BT<std::string>> IncludeDirectoriesEntries;
+  std::vector<std::string> InstallIncludeDirectoriesEntries;
+  std::vector<BT<std::string>> CompileOptionsEntries;
+  std::vector<BT<std::string>> CompileFeaturesEntries;
+  std::vector<BT<std::string>> CompileDefinitionsEntries;
+  std::vector<BT<std::string>> PrecompileHeadersEntries;
+  std::vector<BT<std::string>> SourceEntries;
+  std::vector<BT<std::string>> LinkOptionsEntries;
+  std::vector<BT<std::string>> LinkDirectoriesEntries;
+  std::vector<BT<std::string>> LinkImplementationPropertyEntries;
   std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>>
     TLLCommands;
   cmListFileBacktrace Backtrace;
@@ -265,16 +260,16 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
   auto initProp = [this, mf, &defKey](const std::string& property) {
     // Replace everything after "CMAKE_"
     defKey.replace(defKey.begin() + 6, defKey.end(), property);
-    if (cmProp value = mf->GetDefinition(defKey)) {
-      this->SetProperty(property, *value);
+    if (cmValue value = mf->GetDefinition(defKey)) {
+      this->SetProperty(property, value);
     }
   };
   auto initPropValue = [this, mf, &defKey](const std::string& property,
                                            const char* default_value) {
     // Replace everything after "CMAKE_"
     defKey.replace(defKey.begin() + 6, defKey.end(), property);
-    if (cmProp value = mf->GetDefinition(defKey)) {
-      this->SetProperty(property, *value);
+    if (cmValue value = mf->GetDefinition(defKey)) {
+      this->SetProperty(property, value);
     } else if (default_value) {
       this->SetProperty(property, default_value);
     }
@@ -481,8 +476,6 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
     // of the same directory property:
     cm::append(this->impl->IncludeDirectoriesEntries,
                this->impl->Makefile->GetIncludeDirectoriesEntries());
-    cm::append(this->impl->IncludeDirectoriesBacktraces,
-               this->impl->Makefile->GetIncludeDirectoriesBacktraces());
 
     {
       auto const& sysInc = this->impl->Makefile->GetSystemIncludeDirectories();
@@ -492,18 +485,12 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
 
     cm::append(this->impl->CompileOptionsEntries,
                this->impl->Makefile->GetCompileOptionsEntries());
-    cm::append(this->impl->CompileOptionsBacktraces,
-               this->impl->Makefile->GetCompileOptionsBacktraces());
 
     cm::append(this->impl->LinkOptionsEntries,
                this->impl->Makefile->GetLinkOptionsEntries());
-    cm::append(this->impl->LinkOptionsBacktraces,
-               this->impl->Makefile->GetLinkOptionsBacktraces());
 
     cm::append(this->impl->LinkDirectoriesEntries,
                this->impl->Makefile->GetLinkDirectoriesEntries());
-    cm::append(this->impl->LinkDirectoriesBacktraces,
-               this->impl->Makefile->GetLinkDirectoriesBacktraces());
   }
 
   if (this->impl->TargetType == cmStateEnums::EXECUTABLE) {
@@ -541,7 +528,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
 
   // check for "CMAKE_VS_GLOBALS" variable and set up target properties
   // if any
-  cmProp globals = mf->GetDefinition("CMAKE_VS_GLOBALS");
+  cmValue globals = mf->GetDefinition("CMAKE_VS_GLOBALS");
   if (globals) {
     const std::string genName = mf->GetGlobalGenerator()->GetName();
     if (cmHasLiteralPrefix(genName, "Visual Studio")) {
@@ -612,11 +599,9 @@ void cmTarget::SetLanguageStandardProperty(std::string const& lang,
                                            const std::string& feature)
 {
   cmListFileBacktrace featureBacktrace;
-  for (size_t i = 0; i < this->impl->CompileFeaturesEntries.size(); i++) {
-    if (this->impl->CompileFeaturesEntries[i] == feature) {
-      if (i < this->impl->CompileFeaturesBacktraces.size()) {
-        featureBacktrace = this->impl->CompileFeaturesBacktraces[i];
-      }
+  for (auto const& entry : this->impl->CompileFeaturesEntries) {
+    if (entry.Value == feature) {
+      featureBacktrace = entry.Backtrace;
       break;
     }
   }
@@ -728,8 +713,7 @@ void cmTarget::AddTracedSources(std::vector<std::string> const& srcs)
 {
   if (!srcs.empty()) {
     cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-    this->impl->SourceEntries.push_back(cmJoin(srcs, ";"));
-    this->impl->SourceBacktraces.push_back(lfbt);
+    this->impl->SourceEntries.emplace_back(cmJoin(srcs, ";"), lfbt);
   }
 }
 
@@ -753,8 +737,7 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs)
   }
   if (!srcFiles.empty()) {
     cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-    this->impl->SourceEntries.push_back(std::move(srcFiles));
-    this->impl->SourceBacktraces.push_back(lfbt);
+    this->impl->SourceEntries.emplace_back(std::move(srcFiles), lfbt);
   }
 }
 
@@ -842,9 +825,9 @@ public:
   {
   }
 
-  bool operator()(std::string const& entry)
+  bool operator()(BT<std::string> const& entry)
   {
-    std::vector<std::string> files = cmExpandedList(entry);
+    std::vector<std::string> files = cmExpandedList(entry.Value);
     std::vector<cmSourceFileLocation> locations;
     locations.reserve(files.size());
     std::transform(files.begin(), files.end(), std::back_inserter(locations),
@@ -865,11 +848,7 @@ cmSourceFile* cmTarget::AddSource(const std::string& src, bool before)
     cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
     this->impl->SourceEntries.insert(before ? this->impl->SourceEntries.begin()
                                             : this->impl->SourceEntries.end(),
-                                     src);
-    this->impl->SourceBacktraces.insert(
-      before ? this->impl->SourceBacktraces.begin()
-             : this->impl->SourceBacktraces.end(),
-      lfbt);
+                                     BT<std::string>(src, lfbt));
   }
   if (cmGeneratorExpression::Find(src) != std::string::npos) {
     return nullptr;
@@ -1042,7 +1021,7 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
        this->GetPolicyStatusCMP0073() == cmPolicies::WARN)) {
     std::string targetEntry = cmStrCat(this->impl->Name, "_LIB_DEPENDS");
     std::string dependencies;
-    cmProp old_val = mf.GetDefinition(targetEntry);
+    cmValue old_val = mf.GetDefinition(targetEntry);
     if (old_val) {
       dependencies += *old_val;
     }
@@ -1075,122 +1054,115 @@ std::set<std::string> const& cmTarget::GetSystemIncludeDirectories() const
   return this->impl->SystemIncludeDirectories;
 }
 
-cmStringRange cmTarget::GetIncludeDirectoriesEntries() const
+void cmTarget::AddInstallIncludeDirectories(cmStringRange const& incs)
 {
-  return cmMakeRange(this->impl->IncludeDirectoriesEntries);
+  std::copy(incs.begin(), incs.end(),
+            std::back_inserter(this->impl->InstallIncludeDirectoriesEntries));
 }
 
-cmBacktraceRange cmTarget::GetIncludeDirectoriesBacktraces() const
+cmStringRange cmTarget::GetInstallIncludeDirectoriesEntries() const
 {
-  return cmMakeRange(this->impl->IncludeDirectoriesBacktraces);
+  return cmMakeRange(this->impl->InstallIncludeDirectoriesEntries);
 }
 
-cmStringRange cmTarget::GetCompileOptionsEntries() const
+cmBTStringRange cmTarget::GetIncludeDirectoriesEntries() const
 {
-  return cmMakeRange(this->impl->CompileOptionsEntries);
+  return cmMakeRange(this->impl->IncludeDirectoriesEntries);
 }
 
-cmBacktraceRange cmTarget::GetCompileOptionsBacktraces() const
+cmBTStringRange cmTarget::GetCompileOptionsEntries() const
 {
-  return cmMakeRange(this->impl->CompileOptionsBacktraces);
+  return cmMakeRange(this->impl->CompileOptionsEntries);
 }
 
-cmStringRange cmTarget::GetCompileFeaturesEntries() const
+cmBTStringRange cmTarget::GetCompileFeaturesEntries() const
 {
   return cmMakeRange(this->impl->CompileFeaturesEntries);
 }
 
-cmBacktraceRange cmTarget::GetCompileFeaturesBacktraces() const
-{
-  return cmMakeRange(this->impl->CompileFeaturesBacktraces);
-}
-
-cmStringRange cmTarget::GetCompileDefinitionsEntries() const
+cmBTStringRange cmTarget::GetCompileDefinitionsEntries() const
 {
   return cmMakeRange(this->impl->CompileDefinitionsEntries);
 }
 
-cmBacktraceRange cmTarget::GetCompileDefinitionsBacktraces() const
-{
-  return cmMakeRange(this->impl->CompileDefinitionsBacktraces);
-}
-
-cmStringRange cmTarget::GetPrecompileHeadersEntries() const
+cmBTStringRange cmTarget::GetPrecompileHeadersEntries() const
 {
   return cmMakeRange(this->impl->PrecompileHeadersEntries);
 }
 
-cmBacktraceRange cmTarget::GetPrecompileHeadersBacktraces() const
-{
-  return cmMakeRange(this->impl->PrecompileHeadersBacktraces);
-}
-
-cmStringRange cmTarget::GetSourceEntries() const
+cmBTStringRange cmTarget::GetSourceEntries() const
 {
   return cmMakeRange(this->impl->SourceEntries);
 }
 
-cmBacktraceRange cmTarget::GetSourceBacktraces() const
-{
-  return cmMakeRange(this->impl->SourceBacktraces);
-}
-
-cmStringRange cmTarget::GetLinkOptionsEntries() const
+cmBTStringRange cmTarget::GetLinkOptionsEntries() const
 {
   return cmMakeRange(this->impl->LinkOptionsEntries);
 }
 
-cmBacktraceRange cmTarget::GetLinkOptionsBacktraces() const
+cmBTStringRange cmTarget::GetLinkDirectoriesEntries() const
 {
-  return cmMakeRange(this->impl->LinkOptionsBacktraces);
+  return cmMakeRange(this->impl->LinkDirectoriesEntries);
 }
 
-cmStringRange cmTarget::GetLinkDirectoriesEntries() const
+cmBTStringRange cmTarget::GetLinkImplementationEntries() const
 {
-  return cmMakeRange(this->impl->LinkDirectoriesEntries);
+  return cmMakeRange(this->impl->LinkImplementationPropertyEntries);
 }
 
-cmBacktraceRange cmTarget::GetLinkDirectoriesBacktraces() const
-{
-  return cmMakeRange(this->impl->LinkDirectoriesBacktraces);
+namespace {
+#define MAKE_PROP(PROP) const std::string prop##PROP = #PROP
+MAKE_PROP(C_STANDARD);
+MAKE_PROP(CXX_STANDARD);
+MAKE_PROP(CUDA_STANDARD);
+MAKE_PROP(HIP_STANDARD);
+MAKE_PROP(OBJC_STANDARD);
+MAKE_PROP(OBJCXX_STANDARD);
+MAKE_PROP(COMPILE_DEFINITIONS);
+MAKE_PROP(COMPILE_FEATURES);
+MAKE_PROP(COMPILE_OPTIONS);
+MAKE_PROP(PRECOMPILE_HEADERS);
+MAKE_PROP(PRECOMPILE_HEADERS_REUSE_FROM);
+MAKE_PROP(CUDA_PTX_COMPILATION);
+MAKE_PROP(EXPORT_NAME);
+MAKE_PROP(IMPORTED);
+MAKE_PROP(IMPORTED_GLOBAL);
+MAKE_PROP(INCLUDE_DIRECTORIES);
+MAKE_PROP(LINK_OPTIONS);
+MAKE_PROP(LINK_DIRECTORIES);
+MAKE_PROP(LINK_LIBRARIES);
+MAKE_PROP(MANUALLY_ADDED_DEPENDENCIES);
+MAKE_PROP(NAME);
+MAKE_PROP(SOURCES);
+MAKE_PROP(TYPE);
+MAKE_PROP(BINARY_DIR);
+MAKE_PROP(SOURCE_DIR);
+MAKE_PROP(FALSE);
+MAKE_PROP(TRUE);
+#undef MAKE_PROP
 }
 
-cmStringRange cmTarget::GetLinkImplementationEntries() const
+namespace {
+// to workaround bug on GCC/AIX
+// Define a template to force conversion to std::string
+template <typename ValueType>
+std::string ConvertToString(ValueType value);
+
+template <>
+std::string ConvertToString<const char*>(const char* value)
 {
-  return cmMakeRange(this->impl->LinkImplementationPropertyEntries);
+  return std::string(value);
 }
-
-cmBacktraceRange cmTarget::GetLinkImplementationBacktraces() const
+template <>
+std::string ConvertToString<cmValue>(cmValue value)
 {
-  return cmMakeRange(this->impl->LinkImplementationPropertyBacktraces);
+  return std::string(*value);
+}
 }
 
-void cmTarget::SetProperty(const std::string& prop, const char* value)
+template <typename ValueType>
+void cmTarget::StoreProperty(const std::string& prop, ValueType value)
 {
-#define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP
-  MAKE_STATIC_PROP(C_STANDARD);
-  MAKE_STATIC_PROP(CXX_STANDARD);
-  MAKE_STATIC_PROP(CUDA_STANDARD);
-  MAKE_STATIC_PROP(HIP_STANDARD);
-  MAKE_STATIC_PROP(OBJC_STANDARD);
-  MAKE_STATIC_PROP(OBJCXX_STANDARD);
-  MAKE_STATIC_PROP(COMPILE_DEFINITIONS);
-  MAKE_STATIC_PROP(COMPILE_FEATURES);
-  MAKE_STATIC_PROP(COMPILE_OPTIONS);
-  MAKE_STATIC_PROP(PRECOMPILE_HEADERS);
-  MAKE_STATIC_PROP(PRECOMPILE_HEADERS_REUSE_FROM);
-  MAKE_STATIC_PROP(CUDA_PTX_COMPILATION);
-  MAKE_STATIC_PROP(EXPORT_NAME);
-  MAKE_STATIC_PROP(IMPORTED_GLOBAL);
-  MAKE_STATIC_PROP(INCLUDE_DIRECTORIES);
-  MAKE_STATIC_PROP(LINK_OPTIONS);
-  MAKE_STATIC_PROP(LINK_DIRECTORIES);
-  MAKE_STATIC_PROP(LINK_LIBRARIES);
-  MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
-  MAKE_STATIC_PROP(NAME);
-  MAKE_STATIC_PROP(SOURCES);
-  MAKE_STATIC_PROP(TYPE);
-#undef MAKE_STATIC_PROP
   if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
     this->impl->Makefile->IssueMessage(
       MessageType::FATAL_ERROR,
@@ -1231,75 +1203,57 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
 
   if (prop == propINCLUDE_DIRECTORIES) {
     this->impl->IncludeDirectoriesEntries.clear();
-    this->impl->IncludeDirectoriesBacktraces.clear();
     if (value) {
-      this->impl->IncludeDirectoriesEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->IncludeDirectoriesBacktraces.push_back(lfbt);
+      this->impl->IncludeDirectoriesEntries.emplace_back(value, lfbt);
     }
   } else if (prop == propCOMPILE_OPTIONS) {
     this->impl->CompileOptionsEntries.clear();
-    this->impl->CompileOptionsBacktraces.clear();
     if (value) {
-      this->impl->CompileOptionsEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->CompileOptionsBacktraces.push_back(lfbt);
+      this->impl->CompileOptionsEntries.emplace_back(value, lfbt);
     }
   } else if (prop == propCOMPILE_FEATURES) {
     this->impl->CompileFeaturesEntries.clear();
-    this->impl->CompileFeaturesBacktraces.clear();
     if (value) {
-      this->impl->CompileFeaturesEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->CompileFeaturesBacktraces.push_back(lfbt);
+      this->impl->CompileFeaturesEntries.emplace_back(value, lfbt);
     }
   } else if (prop == propCOMPILE_DEFINITIONS) {
     this->impl->CompileDefinitionsEntries.clear();
-    this->impl->CompileDefinitionsBacktraces.clear();
     if (value) {
-      this->impl->CompileDefinitionsEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->CompileDefinitionsBacktraces.push_back(lfbt);
+      this->impl->CompileDefinitionsEntries.emplace_back(value, lfbt);
     }
   } else if (prop == propLINK_OPTIONS) {
     this->impl->LinkOptionsEntries.clear();
-    this->impl->LinkOptionsBacktraces.clear();
     if (value) {
-      this->impl->LinkOptionsEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->LinkOptionsBacktraces.push_back(lfbt);
+      this->impl->LinkOptionsEntries.emplace_back(value, lfbt);
     }
   } else if (prop == propLINK_DIRECTORIES) {
     this->impl->LinkDirectoriesEntries.clear();
-    this->impl->LinkDirectoriesBacktraces.clear();
     if (value) {
-      this->impl->LinkDirectoriesEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->LinkDirectoriesBacktraces.push_back(lfbt);
+      this->impl->LinkDirectoriesEntries.emplace_back(value, lfbt);
     }
   } else if (prop == propPRECOMPILE_HEADERS) {
     this->impl->PrecompileHeadersEntries.clear();
-    this->impl->PrecompileHeadersBacktraces.clear();
     if (value) {
-      this->impl->PrecompileHeadersEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->PrecompileHeadersBacktraces.push_back(lfbt);
+      this->impl->PrecompileHeadersEntries.emplace_back(value, lfbt);
     }
   } else if (prop == propLINK_LIBRARIES) {
     this->impl->LinkImplementationPropertyEntries.clear();
-    this->impl->LinkImplementationPropertyBacktraces.clear();
     if (value) {
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->LinkImplementationPropertyEntries.emplace_back(value);
-      this->impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
+      this->impl->LinkImplementationPropertyEntries.emplace_back(value, lfbt);
     }
   } else if (prop == propSOURCES) {
     this->impl->SourceEntries.clear();
-    this->impl->SourceBacktraces.clear();
     if (value) {
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->SourceEntries.emplace_back(value);
-      this->impl->SourceBacktraces.push_back(lfbt);
+      this->impl->SourceEntries.emplace_back(value, lfbt);
     }
   } else if (prop == propIMPORTED_GLOBAL) {
     if (!cmIsOn(value)) {
@@ -1315,7 +1269,8 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
       this->GetGlobalGenerator()->IndexTarget(this);
     }
   } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") &&
-             !this->impl->CheckImportedLibName(prop, value ? value : "")) {
+             !this->impl->CheckImportedLibName(
+               prop, value ? value : std::string{})) {
     /* error was reported by check method */
   } else if (prop == propCUDA_PTX_COMPILATION &&
              this->GetType() != cmStateEnums::OBJECT_LIBRARY) {
@@ -1345,17 +1300,17 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
 
     std::string reusedFrom = reusedTarget->GetSafeProperty(prop);
     if (reusedFrom.empty()) {
-      reusedFrom = value;
+      reusedFrom = ConvertToString(value);
     }
 
-    this->impl->Properties.SetProperty(prop, reusedFrom.c_str());
+    this->impl->Properties.SetProperty(prop, reusedFrom);
 
     reusedTarget->SetProperty("COMPILE_PDB_NAME", reusedFrom);
     reusedTarget->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
                               cmStrCat(reusedFrom, ".dir/"));
 
-    cmProp tmp = reusedTarget->GetProperty("COMPILE_PDB_NAME");
-    this->SetProperty("COMPILE_PDB_NAME", cmToCStr(tmp));
+    cmValue tmp = reusedTarget->GetProperty("COMPILE_PDB_NAME");
+    this->SetProperty("COMPILE_PDB_NAME", tmp);
     this->AddUtility(reusedFrom, false, this->impl->Makefile);
   } else if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
              prop == propCUDA_STANDARD || prop == propHIP_STANDARD ||
@@ -1403,39 +1358,33 @@ void cmTarget::AppendProperty(const std::string& prop,
   }
   if (prop == "INCLUDE_DIRECTORIES") {
     if (!value.empty()) {
-      this->impl->IncludeDirectoriesEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->IncludeDirectoriesBacktraces.push_back(lfbt);
+      this->impl->IncludeDirectoriesEntries.emplace_back(value, lfbt);
     }
   } else if (prop == "COMPILE_OPTIONS") {
     if (!value.empty()) {
-      this->impl->CompileOptionsEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->CompileOptionsBacktraces.push_back(lfbt);
+      this->impl->CompileOptionsEntries.emplace_back(value, lfbt);
     }
   } else if (prop == "COMPILE_FEATURES") {
     if (!value.empty()) {
-      this->impl->CompileFeaturesEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->CompileFeaturesBacktraces.push_back(lfbt);
+      this->impl->CompileFeaturesEntries.emplace_back(value, lfbt);
     }
   } else if (prop == "COMPILE_DEFINITIONS") {
     if (!value.empty()) {
-      this->impl->CompileDefinitionsEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->CompileDefinitionsBacktraces.push_back(lfbt);
+      this->impl->CompileDefinitionsEntries.emplace_back(value, lfbt);
     }
   } else if (prop == "LINK_OPTIONS") {
     if (!value.empty()) {
-      this->impl->LinkOptionsEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->LinkOptionsBacktraces.push_back(lfbt);
+      this->impl->LinkOptionsEntries.emplace_back(value, lfbt);
     }
   } else if (prop == "LINK_DIRECTORIES") {
     if (!value.empty()) {
-      this->impl->LinkDirectoriesEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->LinkDirectoriesBacktraces.push_back(lfbt);
+      this->impl->LinkDirectoriesEntries.emplace_back(value, lfbt);
     }
   } else if (prop == "PRECOMPILE_HEADERS") {
     if (this->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
@@ -1447,20 +1396,17 @@ void cmTarget::AppendProperty(const std::string& prop,
       return;
     }
     if (!value.empty()) {
-      this->impl->PrecompileHeadersEntries.emplace_back(value);
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->PrecompileHeadersBacktraces.push_back(lfbt);
+      this->impl->PrecompileHeadersEntries.emplace_back(value, lfbt);
     }
   } else if (prop == "LINK_LIBRARIES") {
     if (!value.empty()) {
       cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-      this->impl->LinkImplementationPropertyEntries.emplace_back(value);
-      this->impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
+      this->impl->LinkImplementationPropertyEntries.emplace_back(value, lfbt);
     }
   } else if (prop == "SOURCES") {
     cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
-    this->impl->SourceEntries.emplace_back(value);
-    this->impl->SourceBacktraces.push_back(lfbt);
+    this->impl->SourceEntries.emplace_back(value, lfbt);
   } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) {
     this->impl->Makefile->IssueMessage(
       MessageType::FATAL_ERROR, prop + " property may not be APPENDed.");
@@ -1474,6 +1420,15 @@ void cmTarget::AppendProperty(const std::string& prop,
   }
 }
 
+void cmTarget::SetProperty(const std::string& prop, const char* value)
+{
+  this->StoreProperty(prop, value);
+}
+void cmTarget::SetProperty(const std::string& prop, cmValue value)
+{
+  this->StoreProperty(prop, value);
+}
+
 void cmTarget::AppendBuildInterfaceIncludes()
 {
   if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
@@ -1501,70 +1456,46 @@ void cmTarget::AppendBuildInterfaceIncludes()
   }
 }
 
-void cmTarget::InsertInclude(std::string const& entry,
-                             cmListFileBacktrace const& bt, bool before)
+void cmTarget::InsertInclude(BT<std::string> const& entry, bool before)
 {
   auto position = before ? this->impl->IncludeDirectoriesEntries.begin()
                          : this->impl->IncludeDirectoriesEntries.end();
 
-  auto btPosition = before ? this->impl->IncludeDirectoriesBacktraces.begin()
-                           : this->impl->IncludeDirectoriesBacktraces.end();
-
   this->impl->IncludeDirectoriesEntries.insert(position, entry);
-  this->impl->IncludeDirectoriesBacktraces.insert(btPosition, bt);
 }
 
-void cmTarget::InsertCompileOption(std::string const& entry,
-                                   cmListFileBacktrace const& bt, bool before)
+void cmTarget::InsertCompileOption(BT<std::string> const& entry, bool before)
 {
   auto position = before ? this->impl->CompileOptionsEntries.begin()
                          : this->impl->CompileOptionsEntries.end();
 
-  auto btPosition = before ? this->impl->CompileOptionsBacktraces.begin()
-                           : this->impl->CompileOptionsBacktraces.end();
-
   this->impl->CompileOptionsEntries.insert(position, entry);
-  this->impl->CompileOptionsBacktraces.insert(btPosition, bt);
 }
 
-void cmTarget::InsertCompileDefinition(std::string const& entry,
-                                       cmListFileBacktrace const& bt)
+void cmTarget::InsertCompileDefinition(BT<std::string> const& entry)
 {
   this->impl->CompileDefinitionsEntries.push_back(entry);
-  this->impl->CompileDefinitionsBacktraces.push_back(bt);
 }
 
-void cmTarget::InsertLinkOption(std::string const& entry,
-                                cmListFileBacktrace const& bt, bool before)
+void cmTarget::InsertLinkOption(BT<std::string> const& entry, bool before)
 {
   auto position = before ? this->impl->LinkOptionsEntries.begin()
                          : this->impl->LinkOptionsEntries.end();
 
-  auto btPosition = before ? this->impl->LinkOptionsBacktraces.begin()
-                           : this->impl->LinkOptionsBacktraces.end();
-
   this->impl->LinkOptionsEntries.insert(position, entry);
-  this->impl->LinkOptionsBacktraces.insert(btPosition, bt);
 }
 
-void cmTarget::InsertLinkDirectory(std::string const& entry,
-                                   cmListFileBacktrace const& bt, bool before)
+void cmTarget::InsertLinkDirectory(BT<std::string> const& entry, bool before)
 {
   auto position = before ? this->impl->LinkDirectoriesEntries.begin()
                          : this->impl->LinkDirectoriesEntries.end();
 
-  auto btPosition = before ? this->impl->LinkDirectoriesBacktraces.begin()
-                           : this->impl->LinkDirectoriesBacktraces.end();
-
   this->impl->LinkDirectoriesEntries.insert(position, entry);
-  this->impl->LinkDirectoriesBacktraces.insert(btPosition, bt);
 }
 
-void cmTarget::InsertPrecompileHeader(std::string const& entry,
-                                      cmListFileBacktrace const& bt)
+void cmTarget::InsertPrecompileHeader(BT<std::string> const& entry)
 {
   this->impl->PrecompileHeadersEntries.push_back(entry);
-  this->impl->PrecompileHeadersBacktraces.push_back(bt);
 }
 
 static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
@@ -1651,17 +1582,17 @@ void cmTarget::CheckProperty(const std::string& prop,
 {
   // Certain properties need checking.
   if (cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES")) {
-    if (cmProp value = this->GetProperty(prop)) {
+    if (cmValue value = this->GetProperty(prop)) {
       cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, *value, context, false);
     }
   }
   if (cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES")) {
-    if (cmProp value = this->GetProperty(prop)) {
+    if (cmValue value = this->GetProperty(prop)) {
       cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, *value, context, true);
     }
   }
   if (prop == "INTERFACE_LINK_LIBRARIES") {
-    if (cmProp value = this->GetProperty(prop)) {
+    if (cmValue value = this->GetProperty(prop)) {
       cmTargetCheckINTERFACE_LINK_LIBRARIES(*value, context);
     }
   }
@@ -1672,40 +1603,15 @@ void cmTarget::CheckProperty(const std::string& prop,
   }
 }
 
-cmProp cmTarget::GetComputedProperty(const std::string& prop,
-                                     cmMessenger* messenger,
-                                     cmListFileBacktrace const& context) const
+cmValue cmTarget::GetComputedProperty(const std::string& prop,
+                                      cmMessenger* messenger,
+                                      cmListFileBacktrace const& context) const
 {
   return cmTargetPropertyComputer::GetProperty(this, prop, messenger, context);
 }
 
-cmProp cmTarget::GetProperty(const std::string& prop) const
-{
-#define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP
-  MAKE_STATIC_PROP(C_STANDARD);
-  MAKE_STATIC_PROP(CXX_STANDARD);
-  MAKE_STATIC_PROP(CUDA_STANDARD);
-  MAKE_STATIC_PROP(OBJC_STANDARD);
-  MAKE_STATIC_PROP(OBJCXX_STANDARD);
-  MAKE_STATIC_PROP(LINK_LIBRARIES);
-  MAKE_STATIC_PROP(TYPE);
-  MAKE_STATIC_PROP(INCLUDE_DIRECTORIES);
-  MAKE_STATIC_PROP(COMPILE_FEATURES);
-  MAKE_STATIC_PROP(COMPILE_OPTIONS);
-  MAKE_STATIC_PROP(COMPILE_DEFINITIONS);
-  MAKE_STATIC_PROP(LINK_OPTIONS);
-  MAKE_STATIC_PROP(LINK_DIRECTORIES);
-  MAKE_STATIC_PROP(PRECOMPILE_HEADERS);
-  MAKE_STATIC_PROP(IMPORTED);
-  MAKE_STATIC_PROP(IMPORTED_GLOBAL);
-  MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
-  MAKE_STATIC_PROP(NAME);
-  MAKE_STATIC_PROP(BINARY_DIR);
-  MAKE_STATIC_PROP(SOURCE_DIR);
-  MAKE_STATIC_PROP(SOURCES);
-  MAKE_STATIC_PROP(FALSE);
-  MAKE_STATIC_PROP(TRUE);
-#undef MAKE_STATIC_PROP
+cmValue cmTarget::GetProperty(const std::string& prop) const
+{
   static std::unordered_set<std::string> const specialProps{
     propC_STANDARD,
     propCXX_STANDARD,
@@ -1737,7 +1643,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
       if (propertyIter == this->impl->LanguageStandardProperties.end()) {
         return nullptr;
       }
-      return &(propertyIter->second.Value);
+      return cmValue(propertyIter->second.Value);
     }
     if (prop == propLINK_LIBRARIES) {
       if (this->impl->LinkImplementationPropertyEntries.empty()) {
@@ -1746,11 +1652,11 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->LinkImplementationPropertyEntries, ";");
-      return &output;
+      return cmValue(output);
     }
     // the type property returns what type the target is
     if (prop == propTYPE) {
-      return &cmState::GetTargetTypeName(this->GetType());
+      return cmValue(cmState::GetTargetTypeName(this->GetType()));
     }
     if (prop == propINCLUDE_DIRECTORIES) {
       if (this->impl->IncludeDirectoriesEntries.empty()) {
@@ -1759,7 +1665,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->IncludeDirectoriesEntries, ";");
-      return &output;
+      return cmValue(output);
     }
     if (prop == propCOMPILE_FEATURES) {
       if (this->impl->CompileFeaturesEntries.empty()) {
@@ -1768,7 +1674,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->CompileFeaturesEntries, ";");
-      return &output;
+      return cmValue(output);
     }
     if (prop == propCOMPILE_OPTIONS) {
       if (this->impl->CompileOptionsEntries.empty()) {
@@ -1777,7 +1683,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->CompileOptionsEntries, ";");
-      return &output;
+      return cmValue(output);
     }
     if (prop == propCOMPILE_DEFINITIONS) {
       if (this->impl->CompileDefinitionsEntries.empty()) {
@@ -1786,7 +1692,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->CompileDefinitionsEntries, ";");
-      return &output;
+      return cmValue(output);
     }
     if (prop == propLINK_OPTIONS) {
       if (this->impl->LinkOptionsEntries.empty()) {
@@ -1795,7 +1701,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->LinkOptionsEntries, ";");
-      return &output;
+      return cmValue(output);
     }
     if (prop == propLINK_DIRECTORIES) {
       if (this->impl->LinkDirectoriesEntries.empty()) {
@@ -1805,7 +1711,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
       static std::string output;
       output = cmJoin(this->impl->LinkDirectoriesEntries, ";");
 
-      return &output;
+      return cmValue(output);
     }
     if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
       if (this->impl->Utilities.empty()) {
@@ -1822,7 +1728,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
           return item.Value.first;
         });
       output = cmJoin(utilities, ";");
-      return &output;
+      return cmValue(output);
     }
     if (prop == propPRECOMPILE_HEADERS) {
       if (this->impl->PrecompileHeadersEntries.empty()) {
@@ -1831,30 +1737,31 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->PrecompileHeadersEntries, ";");
-      return &output;
+      return cmValue(output);
     }
     if (prop == propIMPORTED) {
-      return this->IsImported() ? &propTRUE : &propFALSE;
+      return this->IsImported() ? cmValue(propTRUE) : cmValue(propFALSE);
     }
     if (prop == propIMPORTED_GLOBAL) {
-      return this->IsImportedGloballyVisible() ? &propTRUE : &propFALSE;
+      return this->IsImportedGloballyVisible() ? cmValue(propTRUE)
+                                               : cmValue(propFALSE);
     }
     if (prop == propNAME) {
-      return &this->GetName();
+      return cmValue(this->GetName());
     }
     if (prop == propBINARY_DIR) {
-      return &this->impl->Makefile->GetStateSnapshot()
-                .GetDirectory()
-                .GetCurrentBinary();
+      return cmValue(this->impl->Makefile->GetStateSnapshot()
+                       .GetDirectory()
+                       .GetCurrentBinary());
     }
     if (prop == propSOURCE_DIR) {
-      return &this->impl->Makefile->GetStateSnapshot()
-                .GetDirectory()
-                .GetCurrentSource();
+      return cmValue(this->impl->Makefile->GetStateSnapshot()
+                       .GetDirectory()
+                       .GetCurrentSource());
     }
   }
 
-  cmProp retVal = this->impl->Properties.GetPropertyValue(prop);
+  cmValue retVal = this->impl->Properties.GetPropertyValue(prop);
   if (!retVal) {
     const bool chain = this->impl->Makefile->GetState()->IsPropertyChained(
       prop, cmProperty::TARGET);
@@ -1870,7 +1777,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
 std::string const& cmTarget::GetSafeProperty(std::string const& prop) const
 {
-  cmProp ret = this->GetProperty(prop);
+  cmValue ret = this->GetProperty(prop);
   if (ret) {
     return *ret;
   }
@@ -2031,8 +1938,8 @@ std::string cmTarget::ImportedGetFullPath(
 
   std::string result;
 
-  cmProp loc = nullptr;
-  cmProp imp = nullptr;
+  cmValue loc = nullptr;
+  cmValue imp = nullptr;
   std::string suffix;
 
   if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
@@ -2043,9 +1950,9 @@ std::string cmTarget::ImportedGetFullPath(
           result = *loc;
         } else {
           std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix);
-          if (cmProp config_location = this->GetProperty(impProp)) {
+          if (cmValue config_location = this->GetProperty(impProp)) {
             result = *config_location;
-          } else if (cmProp location =
+          } else if (cmValue location =
                        this->GetProperty("IMPORTED_LOCATION")) {
             result = *location;
           }
@@ -2058,9 +1965,9 @@ std::string cmTarget::ImportedGetFullPath(
         } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
                    this->IsExecutableWithExports()) {
           std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix);
-          if (cmProp config_implib = this->GetProperty(impProp)) {
+          if (cmValue config_implib = this->GetProperty(impProp)) {
             result = *config_implib;
-          } else if (cmProp implib = this->GetProperty("IMPORTED_IMPLIB")) {
+          } else if (cmValue implib = this->GetProperty("IMPORTED_IMPLIB")) {
             result = *implib;
           }
         }
@@ -2138,8 +2045,8 @@ bool cmTargetInternals::CheckImportedLibName(std::string const& prop,
   return true;
 }
 
-bool cmTarget::GetMappedConfig(std::string const& desired_config, cmProp& loc,
-                               cmProp& imp, std::string& suffix) const
+bool cmTarget::GetMappedConfig(std::string const& desired_config, cmValue& loc,
+                               cmValue& imp, std::string& suffix) const
 {
   std::string config_upper;
   if (!desired_config.empty()) {
@@ -2161,7 +2068,7 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config, cmProp& loc,
   std::vector<std::string> mappedConfigs;
   {
     std::string mapProp = cmStrCat("MAP_IMPORTED_CONFIG_", config_upper);
-    if (cmProp mapValue = this->GetProperty(mapProp)) {
+    if (cmValue mapValue = this->GetProperty(mapProp)) {
       cmExpandList(*mapValue, mappedConfigs, true);
     }
   }
@@ -2243,7 +2150,7 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config, cmProp& loc,
   // any available configuration.
   if (!loc && !imp) {
     std::vector<std::string> availableConfigs;
-    if (cmProp iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS")) {
+    if (cmValue iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS")) {
       cmExpandList(*iconfigs, availableConfigs);
     }
     for (auto aci = availableConfigs.begin();
index 30d9f5d..3cf6942 100644 (file)
 #include "cmAlgorithms.h"
 #include "cmListFileCache.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmTargetLinkLibraryType.h"
+#include "cmValue.h"
 
 class cmCustomCommand;
 class cmGlobalGenerator;
@@ -170,20 +170,21 @@ public:
 
   //! Set/Get a property of this target file
   void SetProperty(const std::string& prop, const char* value);
+  void SetProperty(const std::string& prop, cmValue value);
   void SetProperty(const std::string& prop, const std::string& value)
   {
-    this->SetProperty(prop, value.c_str());
+    this->SetProperty(prop, cmValue(value));
   }
   void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString = false);
   //! Might return a nullptr if the property is not set or invalid
-  cmProp GetProperty(const std::string& prop) const;
+  cmValue GetProperty(const std::string& prop) const;
   //! Always returns a valid pointer
   std::string const& GetSafeProperty(std::string const& prop) const;
   bool GetPropertyAsBool(const std::string& prop) const;
   void CheckProperty(const std::string& prop, cmMakefile* context) const;
-  cmProp GetComputedProperty(const std::string& prop, cmMessenger* messenger,
-                             cmListFileBacktrace const& context) const;
+  cmValue GetComputedProperty(const std::string& prop, cmMessenger* messenger,
+                              cmListFileBacktrace const& context) const;
   //! Get all properties
   cmPropertyMap const& GetProperties() const;
 
@@ -198,8 +199,8 @@ public:
   bool IsPerConfig() const;
   bool CanCompileSources() const;
 
-  bool GetMappedConfig(std::string const& desired_config, cmProp& loc,
-                       cmProp& imp, std::string& suffix) const;
+  bool GetMappedConfig(std::string const& desired_config, cmValue& loc,
+                       cmValue& imp, std::string& suffix) const;
 
   //! Return whether this target is an executable with symbol exports enabled.
   bool IsExecutableWithExports() const;
@@ -216,18 +217,12 @@ public:
   //! Get a backtrace from the creation of the target.
   cmListFileBacktrace const& GetBacktrace() const;
 
-  void InsertInclude(std::string const& entry, cmListFileBacktrace const& bt,
-                     bool before = false);
-  void InsertCompileOption(std::string const& entry,
-                           cmListFileBacktrace const& bt, bool before = false);
-  void InsertCompileDefinition(std::string const& entry,
-                               cmListFileBacktrace const& bt);
-  void InsertLinkOption(std::string const& entry,
-                        cmListFileBacktrace const& bt, bool before = false);
-  void InsertLinkDirectory(std::string const& entry,
-                           cmListFileBacktrace const& bt, bool before = false);
-  void InsertPrecompileHeader(std::string const& entry,
-                              cmListFileBacktrace const& bt);
+  void InsertInclude(BT<std::string> const& entry, bool before = false);
+  void InsertCompileOption(BT<std::string> const& entry, bool before = false);
+  void InsertCompileDefinition(BT<std::string> const& entry);
+  void InsertLinkOption(BT<std::string> const& entry, bool before = false);
+  void InsertLinkDirectory(BT<std::string> const& entry, bool before = false);
+  void InsertPrecompileHeader(BT<std::string> const& entry);
 
   void AppendBuildInterfaceIncludes();
 
@@ -237,6 +232,9 @@ public:
   void AddSystemIncludeDirectories(std::set<std::string> const& incs);
   std::set<std::string> const& GetSystemIncludeDirectories() const;
 
+  void AddInstallIncludeDirectories(cmStringRange const& incs);
+  cmStringRange GetInstallIncludeDirectoriesEntries() const;
+
   BTs<std::string> const* GetLanguageStandardProperty(
     const std::string& propertyName) const;
 
@@ -244,32 +242,23 @@ public:
                                    std::string const& value,
                                    const std::string& feature);
 
-  cmStringRange GetIncludeDirectoriesEntries() const;
-  cmBacktraceRange GetIncludeDirectoriesBacktraces() const;
+  cmBTStringRange GetIncludeDirectoriesEntries() const;
 
-  cmStringRange GetCompileOptionsEntries() const;
-  cmBacktraceRange GetCompileOptionsBacktraces() const;
+  cmBTStringRange GetCompileOptionsEntries() const;
 
-  cmStringRange GetCompileFeaturesEntries() const;
-  cmBacktraceRange GetCompileFeaturesBacktraces() const;
+  cmBTStringRange GetCompileFeaturesEntries() const;
 
-  cmStringRange GetCompileDefinitionsEntries() const;
-  cmBacktraceRange GetCompileDefinitionsBacktraces() const;
+  cmBTStringRange GetCompileDefinitionsEntries() const;
 
-  cmStringRange GetPrecompileHeadersEntries() const;
-  cmBacktraceRange GetPrecompileHeadersBacktraces() const;
+  cmBTStringRange GetPrecompileHeadersEntries() const;
 
-  cmStringRange GetSourceEntries() const;
-  cmBacktraceRange GetSourceBacktraces() const;
+  cmBTStringRange GetSourceEntries() const;
 
-  cmStringRange GetLinkOptionsEntries() const;
-  cmBacktraceRange GetLinkOptionsBacktraces() const;
+  cmBTStringRange GetLinkOptionsEntries() const;
 
-  cmStringRange GetLinkDirectoriesEntries() const;
-  cmBacktraceRange GetLinkDirectoriesBacktraces() const;
+  cmBTStringRange GetLinkDirectoriesEntries() const;
 
-  cmStringRange GetLinkImplementationEntries() const;
-  cmBacktraceRange GetLinkImplementationBacktraces() const;
+  cmBTStringRange GetLinkImplementationEntries() const;
 
   std::string ImportedGetFullPath(const std::string& config,
                                   cmStateEnums::ArtifactType artifact) const;
@@ -280,6 +269,9 @@ public:
   };
 
 private:
+  template <typename ValueType>
+  void StoreProperty(const std::string& prop, ValueType value);
+
   // Internal representation details.
   friend class cmGeneratorTarget;
 
index dee2c10..8ca3842 100644 (file)
@@ -37,7 +37,8 @@ private:
     }
 
     cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-    tgt->InsertCompileOption(this->Join(content), lfbt, prepend);
+    tgt->InsertCompileOption(BT<std::string>(this->Join(content), lfbt),
+                             prepend);
     return true; // Successfully handled.
   }
 
index 1e38d84..19fc931 100644 (file)
@@ -29,7 +29,6 @@ public:
   cmInstallTargetGenerator* FrameworkGenerator;
   cmInstallTargetGenerator* BundleGenerator;
   cmInstallFilesGenerator* HeaderGenerator;
-  std::string InterfaceIncludeDirectories;
   ///@}
 
   bool NamelinkOnly = false;
index 3897499..f31501e 100644 (file)
@@ -63,7 +63,7 @@ bool TargetIncludeDirectoriesImpl::HandleDirectContent(
   bool system)
 {
   cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-  tgt->InsertInclude(this->Join(content), lfbt, prepend);
+  tgt->InsertInclude(BT<std::string>(this->Join(content), lfbt), prepend);
   if (system) {
     std::string prefix = this->Makefile->GetCurrentSourceDirectory() + "/";
     std::set<std::string> sdirs;
index 0c68d60..3ba27a8 100644 (file)
@@ -34,7 +34,8 @@ private:
                            bool prepend, bool /*system*/) override
   {
     cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-    tgt->InsertLinkDirectory(this->Join(content), lfbt, prepend);
+    tgt->InsertLinkDirectory(BT<std::string>(this->Join(content), lfbt),
+                             prepend);
     return true; // Successfully handled.
   }
 };
index 3423b30..e15c941 100644 (file)
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTargetLinkLibraryType.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 namespace {
@@ -143,6 +143,7 @@ bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args,
       case cmPolicies::WARN:
         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0039) << "\n";
         modal = "should";
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         break;
       case cmPolicies::REQUIRED_ALWAYS:
@@ -150,6 +151,7 @@ bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args,
       case cmPolicies::NEW:
         modal = "must";
         messageType = MessageType::FATAL_ERROR;
+        break;
     }
     if (modal) {
       e << "Utility target \"" << target->GetName() << "\" " << modal
@@ -278,7 +280,7 @@ bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args,
       // with old versions of CMake and new)
       llt = GENERAL_LibraryType;
       std::string linkType = cmStrCat(args[0], "_LINK_TYPE");
-      cmProp linkTypeString = mf.GetDefinition(linkType);
+      cmValue linkTypeString = mf.GetDefinition(linkType);
       if (linkTypeString) {
         if (*linkTypeString == "debug") {
           llt = DEBUG_LibraryType;
@@ -395,6 +397,7 @@ bool TLL::HandleLibrary(ProcessingState currentProcessingState,
       case cmPolicies::WARN:
         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0023) << "\n";
         modal = "should";
+        CM_FALLTHROUGH;
       case cmPolicies::OLD:
         break;
       case cmPolicies::REQUIRED_ALWAYS:
@@ -402,6 +405,7 @@ bool TLL::HandleLibrary(ProcessingState currentProcessingState,
       case cmPolicies::NEW:
         modal = "must";
         messageType = MessageType::FATAL_ERROR;
+        break;
     }
 
     if (modal) {
index df9416f..3ea2d71 100644 (file)
@@ -30,7 +30,7 @@ private:
                            bool prepend, bool /*system*/) override
   {
     cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-    tgt->InsertLinkOption(this->Join(content), lfbt, prepend);
+    tgt->InsertLinkOption(BT<std::string>(this->Join(content), lfbt), prepend);
     return true; // Successfully handled.
   }
 
index e41714a..3bd1ea3 100644 (file)
@@ -5,9 +5,9 @@
 #include "cmExecutionStatus.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmTarget.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 cmTargetPropCommandBase::cmTargetPropCommandBase(cmExecutionStatus& status)
@@ -181,7 +181,7 @@ void cmTargetPropCommandBase::HandleInterfaceContent(
 {
   if (prepend) {
     const std::string propName = std::string("INTERFACE_") + this->Property;
-    cmProp propValue = tgt->GetProperty(propName);
+    cmValue propValue = tgt->GetProperty(propName);
     const std::string totalContent =
       this->Join(content) + (propValue ? (";" + *propValue) : std::string());
     tgt->SetProperty(propName, totalContent);
index b9c9365..9b94142 100644 (file)
@@ -21,6 +21,7 @@ bool cmTargetPropertyComputer::HandleLocationPropertyPolicy(
     case cmPolicies::WARN:
       e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0026) << "\n";
       modal = "should";
+      CM_FALLTHROUGH;
     case cmPolicies::OLD:
       break;
     case cmPolicies::REQUIRED_ALWAYS:
@@ -28,6 +29,7 @@ bool cmTargetPropertyComputer::HandleLocationPropertyPolicy(
     case cmPolicies::NEW:
       modal = "may";
       messageType = MessageType::FATAL_ERROR;
+      break;
   }
 
   if (modal) {
index f2be318..e61a1fc 100644 (file)
@@ -7,10 +7,10 @@
 #include <string>
 
 #include "cmListFileCache.h"
-#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 class cmMessenger;
 
@@ -18,11 +18,11 @@ class cmTargetPropertyComputer
 {
 public:
   template <typename Target>
-  static cmProp GetProperty(Target const* tgt, const std::string& prop,
-                            cmMessenger* messenger,
-                            cmListFileBacktrace const& context)
+  static cmValue GetProperty(Target const* tgt, const std::string& prop,
+                             cmMessenger* messenger,
+                             cmListFileBacktrace const& context)
   {
-    if (cmProp loc = GetLocation(tgt, prop, messenger, context)) {
+    if (cmValue loc = GetLocation(tgt, prop, messenger, context)) {
       return loc;
     }
     if (cmSystemTools::GetFatalErrorOccured()) {
@@ -46,9 +46,9 @@ private:
                                             std::string const& config);
 
   template <typename Target>
-  static cmProp GetLocation(Target const* tgt, std::string const& prop,
-                            cmMessenger* messenger,
-                            cmListFileBacktrace const& context)
+  static cmValue GetLocation(Target const* tgt, std::string const& prop,
+                             cmMessenger* messenger,
+                             cmListFileBacktrace const& context)
 
   {
     // Watch for special "computed" properties that are dependent on
@@ -65,7 +65,7 @@ private:
                                           context)) {
           return nullptr;
         }
-        return &ComputeLocationForBuild(tgt);
+        return cmValue(ComputeLocationForBuild(tgt));
       }
 
       // Support "LOCATION_<CONFIG>".
@@ -76,7 +76,7 @@ private:
           return nullptr;
         }
         std::string configName = prop.substr(9);
-        return &ComputeLocation(tgt, configName);
+        return cmValue(ComputeLocation(tgt, configName));
       }
 
       // Support "<CONFIG>_LOCATION".
@@ -89,7 +89,7 @@ private:
                                             context)) {
             return nullptr;
           }
-          return &ComputeLocation(tgt, configName);
+          return cmValue(ComputeLocation(tgt, configName));
         }
       }
     }
@@ -97,6 +97,6 @@ private:
   }
 
   template <typename Target>
-  static cmProp GetSources(Target const* tgt, cmMessenger* messenger,
-                           cmListFileBacktrace const& context);
+  static cmValue GetSources(Target const* tgt, cmMessenger* messenger,
+                            cmListFileBacktrace const& context);
 };
index a26bef3..7c0f9e7 100644 (file)
@@ -5,7 +5,7 @@
 #include "cmMakefile.h"
 #include "cmProperty.h"
 #include "cmState.h"
-#include "cmStringAlgorithms.h"
+#include "cmValue.h"
 
 cmTest::cmTest(cmMakefile* mf)
   : CommandExpandLists(false)
@@ -32,20 +32,20 @@ void cmTest::SetCommand(std::vector<std::string> const& command)
   this->Command = command;
 }
 
-const char* cmTest::GetProperty(const std::string& prop) const
+cmValue cmTest::GetProperty(const std::string& prop) const
 {
-  cmProp retVal = this->Properties.GetPropertyValue(prop);
+  cmValue retVal = this->Properties.GetPropertyValue(prop);
   if (!retVal) {
     const bool chain =
       this->Makefile->GetState()->IsPropertyChained(prop, cmProperty::TEST);
     if (chain) {
-      if (cmProp p = this->Makefile->GetProperty(prop, chain)) {
-        return p->c_str();
+      if (cmValue p = this->Makefile->GetProperty(prop, chain)) {
+        return p;
       }
     }
     return nullptr;
   }
-  return retVal->c_str();
+  return retVal;
 }
 
 bool cmTest::GetPropertyAsBool(const std::string& prop) const
@@ -57,6 +57,10 @@ void cmTest::SetProperty(const std::string& prop, const char* value)
 {
   this->Properties.SetProperty(prop, value);
 }
+void cmTest::SetProperty(const std::string& prop, cmValue value)
+{
+  this->Properties.SetProperty(prop, value);
+}
 
 void cmTest::AppendProperty(const std::string& prop, const std::string& value,
                             bool asString)
index f33b7e2..85978da 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "cmListFileCache.h"
 #include "cmPropertyMap.h"
+#include "cmValue.h"
 
 class cmMakefile;
 
@@ -34,9 +35,14 @@ public:
 
   //! Set/Get a property of this source file
   void SetProperty(const std::string& prop, const char* value);
+  void SetProperty(const std::string& prop, cmValue value);
+  void SetProperty(const std::string& prop, const std::string& value)
+  {
+    this->SetProperty(prop, cmValue(value));
+  }
   void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString = false);
-  const char* GetProperty(const std::string& prop) const;
+  cmValue GetProperty(const std::string& prop) const;
   bool GetPropertyAsBool(const std::string& prop) const;
   cmPropertyMap& GetProperties() { return this->Properties; }
 
index 7022c4e..dbb0876 100644 (file)
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
-#include "cmProperty.h"
 #include "cmPropertyMap.h"
 #include "cmRange.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTest.h"
+#include "cmValue.h"
 
 namespace /* anonymous */
 {
@@ -167,7 +167,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
     exe = target->GetFullPath(config);
 
     // Prepend with the emulator when cross compiling if required.
-    cmProp emulator = target->GetProperty("CROSSCOMPILING_EMULATOR");
+    cmValue emulator = target->GetProperty("CROSSCOMPILING_EMULATOR");
     if (cmNonempty(emulator)) {
       std::vector<std::string> emulatorWithArgs = cmExpandedList(*emulator);
       std::string emulatorExe(emulatorWithArgs[0]);
index 056696d..c8f5a4b 100644 (file)
 #include <cstring>
 #include <sstream>
 
+#ifdef __MINGW32__
+#  include <libloaderapi.h>
+#endif
+
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
@@ -159,6 +163,7 @@ std::string cmTimestamp::AddTimestampComponent(char flag,
     case 'M':
     case 'S':
     case 'U':
+    case 'V':
     case 'w':
     case 'y':
     case 'Y':
@@ -189,6 +194,30 @@ std::string cmTimestamp::AddTimestampComponent(char flag,
 
   char buffer[16];
 
+#ifdef __MINGW32__
+  /* See a bug in MinGW: https://sourceforge.net/p/mingw-w64/bugs/793/. A work
+   * around is to try to use strftime() from ucrtbase.dll. */
+  using T = size_t(WINAPI*)(char*, size_t, const char*, const struct tm*);
+  auto loadUcrtStrftime = []() -> T {
+    auto handle =
+      LoadLibraryExA("ucrtbase.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
+    if (handle) {
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wcast-function-type"
+      return reinterpret_cast<T>(GetProcAddress(handle, "strftime"));
+#  pragma GCC diagnostic pop
+    }
+    return nullptr;
+  };
+  static T ucrtStrftime = loadUcrtStrftime();
+
+  if (ucrtStrftime) {
+    size_t size =
+      ucrtStrftime(buffer, sizeof(buffer), formatString.c_str(), &timeStruct);
+    return std::string(buffer, size);
+  }
+#endif
+
   size_t size =
     strftime(buffer, sizeof(buffer), formatString.c_str(), &timeStruct);
 
index 8cac74d..cc9e158 100644 (file)
@@ -9,12 +9,12 @@
 #include "cmDuration.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 
 class cmExecutionStatus;
@@ -162,7 +162,7 @@ bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv,
       if (!this->OutputVariable.empty()) {
         // if the TryCompileCore saved output in this outputVariable then
         // prepend that output to this output
-        cmProp compileOutput =
+        cmValue compileOutput =
           this->Makefile->GetDefinition(this->OutputVariable);
         if (compileOutput) {
           runOutputContents = *compileOutput + runOutputContents;
@@ -260,7 +260,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
                                        comment.c_str(), cmStateEnums::STRING);
 
     cmState* state = this->Makefile->GetState();
-    cmProp existingValue = state->GetCacheEntryValue(this->RunResultVariable);
+    cmValue existingValue = state->GetCacheEntryValue(this->RunResultVariable);
     if (existingValue) {
       state->SetCacheEntryProperty(this->RunResultVariable, "ADVANCED", "1");
     }
@@ -282,7 +282,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
         internalRunOutputName, "PLEASE_FILL_OUT-NOTFOUND", comment.c_str(),
         cmStateEnums::STRING);
       cmState* state = this->Makefile->GetState();
-      cmProp existing = state->GetCacheEntryValue(internalRunOutputName);
+      cmValue existing = state->GetCacheEntryValue(internalRunOutputName);
       if (existing) {
         state->SetCacheEntryProperty(internalRunOutputName, "ADVANCED", "1");
       }
index 8c5ad59..027d690 100644 (file)
@@ -23,7 +23,7 @@
 
 #else
 
-#  define CM_INHERIT_CTOR(Class, Base, Tpl) using Base Tpl ::Base;
+#  define CM_INHERIT_CTOR(Class, Base, Tpl) using Base Tpl ::Base
 
 #endif
 
index d276c8a..2805a33 100644 (file)
@@ -6,11 +6,11 @@
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 // cmUtilitySourceCommand
 bool cmUtilitySourceCommand(std::vector<std::string> const& args,
@@ -25,7 +25,7 @@ bool cmUtilitySourceCommand(std::vector<std::string> const& args,
 
   // The first argument is the cache entry name.
   std::string const& cacheEntry = *arg++;
-  cmProp cacheValue = status.GetMakefile().GetDefinition(cacheEntry);
+  cmValue cacheValue = status.GetMakefile().GetDefinition(cacheEntry);
   // If it exists already and appears up to date then we are done.  If
   // the string contains "(IntDir)" but that is not the
   // CMAKE_CFG_INTDIR setting then the value is out of date.
@@ -85,7 +85,7 @@ bool cmUtilitySourceCommand(std::vector<std::string> const& args,
   std::string utilityDirectory =
     status.GetMakefile().GetCurrentBinaryDirectory();
   std::string exePath;
-  if (cmProp d =
+  if (cmValue d =
         status.GetMakefile().GetDefinition("EXECUTABLE_OUTPUT_PATH")) {
     exePath = *d;
   }
diff --git a/Source/cmValue.cxx b/Source/cmValue.cxx
new file mode 100644 (file)
index 0000000..044db29
--- /dev/null
@@ -0,0 +1,123 @@
+
+#include "cmValue.h"
+
+#include <string>
+
+#include <cmext/string_view>
+
+#include "cmStringAlgorithms.h"
+
+std::string cmValue::Empty;
+
+bool cmValue::IsOn(cm::string_view value) noexcept
+{
+  switch (value.size()) {
+    case 1:
+      return value[0] == '1' || value[0] == 'Y' || value[0] == 'y';
+    case 2:
+      return                                    //
+        (value[0] == 'O' || value[0] == 'o') && //
+        (value[1] == 'N' || value[1] == 'n');
+    case 3:
+      return                                    //
+        (value[0] == 'Y' || value[0] == 'y') && //
+        (value[1] == 'E' || value[1] == 'e') && //
+        (value[2] == 'S' || value[2] == 's');
+    case 4:
+      return                                    //
+        (value[0] == 'T' || value[0] == 't') && //
+        (value[1] == 'R' || value[1] == 'r') && //
+        (value[2] == 'U' || value[2] == 'u') && //
+        (value[3] == 'E' || value[3] == 'e');
+    default:
+      break;
+  }
+
+  return false;
+}
+
+bool cmValue::IsOff(cm::string_view value) noexcept
+{
+  switch (value.size()) {
+    case 0:
+      return true;
+    case 1:
+      return value[0] == '0' || value[0] == 'N' || value[0] == 'n';
+    case 2:
+      return                                    //
+        (value[0] == 'N' || value[0] == 'n') && //
+        (value[1] == 'O' || value[1] == 'o');
+    case 3:
+      return                                    //
+        (value[0] == 'O' || value[0] == 'o') && //
+        (value[1] == 'F' || value[1] == 'f') && //
+        (value[2] == 'F' || value[2] == 'f');
+    case 5:
+      return                                    //
+        (value[0] == 'F' || value[0] == 'f') && //
+        (value[1] == 'A' || value[1] == 'a') && //
+        (value[2] == 'L' || value[2] == 'l') && //
+        (value[3] == 'S' || value[3] == 's') && //
+        (value[4] == 'E' || value[4] == 'e');
+    case 6:
+      return                                    //
+        (value[0] == 'I' || value[0] == 'i') && //
+        (value[1] == 'G' || value[1] == 'g') && //
+        (value[2] == 'N' || value[2] == 'n') && //
+        (value[3] == 'O' || value[3] == 'o') && //
+        (value[4] == 'R' || value[4] == 'r') && //
+        (value[5] == 'E' || value[5] == 'e');
+    default:
+      break;
+  }
+
+  return IsNOTFOUND(value);
+}
+
+bool cmValue::IsNOTFOUND(cm::string_view value) noexcept
+{
+  return (value == "NOTFOUND"_s) || cmHasSuffix(value, "-NOTFOUND"_s);
+}
+
+bool cmValue::IsInternallyOn(cm::string_view value) noexcept
+{
+  return (value.size() == 4) &&             //
+    (value[0] == 'I' || value[0] == 'i') && //
+    (value[1] == '_') &&                    //
+    (value[2] == 'O' || value[2] == 'o') && //
+    (value[3] == 'N' || value[3] == 'n');
+}
+
+int cmValue::Compare(cmValue value) const noexcept
+{
+  if (this->Value == nullptr && !value) {
+    return 0;
+  }
+  if (this->Value == nullptr) {
+    return -1;
+  }
+  if (!value) {
+    return 1;
+  }
+  return this->Value->compare(*value);
+}
+
+int cmValue::Compare(cm::string_view value) const noexcept
+{
+  if (this->Value == nullptr && value.data() == nullptr) {
+    return 0;
+  }
+  if (this->Value == nullptr) {
+    return -1;
+  }
+  if (value.data() == nullptr) {
+    return 1;
+  }
+  return cm::string_view(*this->Value).compare(value);
+}
+
+std::ostream& operator<<(std::ostream& o, cmValue v)
+{
+  o << *v;
+  return o;
+}
diff --git a/Source/cmValue.h b/Source/cmValue.h
new file mode 100644 (file)
index 0000000..f96d2f5
--- /dev/null
@@ -0,0 +1,314 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <cstddef>
+#include <iosfwd>
+#include <string>
+
+#include <cm/string_view>
+
+class cmValue
+{
+public:
+  cmValue() noexcept = default;
+  cmValue(std::nullptr_t) noexcept {}
+  explicit cmValue(const std::string* value) noexcept
+    : Value(value)
+  {
+  }
+  explicit cmValue(const std::string& value) noexcept
+    : Value(&value)
+  {
+  }
+  cmValue(const cmValue& other) noexcept = default;
+
+  cmValue& operator=(const cmValue& other) noexcept = default;
+  cmValue& operator=(std::nullptr_t) noexcept
+  {
+    this->Value = nullptr;
+    return *this;
+  }
+
+  const std::string* Get() const noexcept { return this->Value; }
+  const char* GetCStr() const noexcept
+  {
+    return this->Value == nullptr ? nullptr : this->Value->c_str();
+  }
+
+  const std::string* operator->() const noexcept
+  {
+    return this->Value == nullptr ? &cmValue::Empty : this->Value;
+  }
+  const std::string& operator*() const noexcept
+  {
+    return this->Value == nullptr ? cmValue::Empty : *this->Value;
+  }
+
+  explicit operator bool() const noexcept { return this->Value != nullptr; }
+  operator const std::string&() const noexcept { return this->operator*(); }
+  explicit operator cm::string_view() const noexcept
+  {
+    return this->operator*();
+  }
+
+  /**
+   * Does the value indicate a true or ON value?
+   */
+  bool IsOn() const noexcept
+  {
+    return this->Value != nullptr &&
+      cmValue::IsOn(cm::string_view(*this->Value));
+  }
+  /**
+   * Does the value indicate a false or off value ? Note that this is
+   * not the same as !IsOn(...) because there are a number of
+   * ambiguous values such as "/usr/local/bin" a path will result in
+   * IsOn and IsOff both returning false. Note that the special path
+   * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true.
+   */
+  bool IsOff() const noexcept
+  {
+    return this->Value == nullptr ||
+      cmValue::IsOff(cm::string_view(*this->Value));
+  }
+  /** Return true if value is NOTFOUND or ends in -NOTFOUND.  */
+  bool IsNOTFOUND() const noexcept
+  {
+    return this->Value != nullptr &&
+      cmValue::IsNOTFOUND(cm::string_view(*this->Value));
+  }
+  bool IsEmpty() const noexcept
+  {
+    return this->Value == nullptr || this->Value->empty();
+  }
+
+  /**
+   * Does a string indicates that CMake/CPack/CTest internally
+   *  forced this value. This is not the same as On, but this
+   * may be considered as "internally switched on".
+   */
+  bool IsInternallyOn() const noexcept
+  {
+    return this->Value != nullptr &&
+      cmValue::IsInternallyOn(cm::string_view(*this->Value));
+  }
+
+  bool IsSet() const noexcept
+  {
+    return !this->IsEmpty() && !this->IsNOTFOUND();
+  }
+
+  /**
+   * Does a string indicate a true or ON value?
+   */
+  static bool IsOn(const char* value) noexcept
+  {
+    return value != nullptr && IsOn(cm::string_view(value));
+  }
+  static bool IsOn(cm::string_view) noexcept;
+
+  /**
+   * Compare method has same semantic as std::optional::compare
+   */
+  int Compare(cmValue value) const noexcept;
+  int Compare(cm::string_view value) const noexcept;
+
+  /**
+   * Does a string indicate a false or off value ? Note that this is
+   * not the same as !IsOn(...) because there are a number of
+   * ambiguous values such as "/usr/local/bin" a path will result in
+   * IsOn and IsOff both returning false. Note that the special path
+   * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true.
+   */
+  static bool IsOff(const char* value) noexcept
+  {
+    return value == nullptr || IsOff(cm::string_view(value));
+  }
+  static bool IsOff(cm::string_view) noexcept;
+
+  /** Return true if value is NOTFOUND or ends in -NOTFOUND.  */
+  static bool IsNOTFOUND(const char* value) noexcept
+  {
+    return value == nullptr || IsNOTFOUND(cm::string_view(value));
+  }
+  static bool IsNOTFOUND(cm::string_view) noexcept;
+
+  static bool IsEmpty(const char* value) noexcept
+  {
+    return value == nullptr || *value == '\0';
+  }
+  static bool IsEmpty(cm::string_view value) noexcept { return value.empty(); }
+
+  /**
+   * Does a string indicates that CMake/CPack/CTest internally
+   * forced this value. This is not the same as On, but this
+   * may be considered as "internally switched on".
+   */
+  static bool IsInternallyOn(const char* value) noexcept
+  {
+    return value != nullptr && IsInternallyOn(cm::string_view(value));
+  }
+  static bool IsInternallyOn(cm::string_view) noexcept;
+
+private:
+  static std::string Empty;
+  const std::string* Value = nullptr;
+};
+
+std::ostream& operator<<(std::ostream& o, cmValue v);
+
+inline bool operator==(cmValue l, cmValue r) noexcept
+{
+  return l.Compare(r) == 0;
+}
+inline bool operator!=(cmValue l, cmValue r) noexcept
+{
+  return l.Compare(r) != 0;
+}
+inline bool operator<(cmValue l, cmValue r) noexcept
+{
+  return l.Compare(r) < 0;
+}
+inline bool operator<=(cmValue l, cmValue r) noexcept
+{
+  return l.Compare(r) <= 0;
+}
+inline bool operator>(cmValue l, cmValue r) noexcept
+{
+  return l.Compare(r) > 0;
+}
+inline bool operator>=(cmValue l, cmValue r) noexcept
+{
+  return l.Compare(r) >= 0;
+}
+
+inline bool operator==(cmValue l, cm::string_view r) noexcept
+{
+  return l.Compare(r) == 0;
+}
+inline bool operator!=(cmValue l, cm::string_view r) noexcept
+{
+  return l.Compare(r) != 0;
+}
+inline bool operator<(cmValue l, cm::string_view r) noexcept
+{
+  return l.Compare(r) < 0;
+}
+inline bool operator<=(cmValue l, cm::string_view r) noexcept
+{
+  return l.Compare(r) <= 0;
+}
+inline bool operator>(cmValue l, cm::string_view r) noexcept
+{
+  return l.Compare(r) > 0;
+}
+inline bool operator>=(cmValue l, cm::string_view r) noexcept
+{
+  return l.Compare(r) >= 0;
+}
+
+inline bool operator==(cmValue l, std::nullptr_t) noexcept
+{
+  return l.Compare(cmValue{}) == 0;
+}
+inline bool operator!=(cmValue l, std::nullptr_t) noexcept
+{
+  return l.Compare(cmValue{}) != 0;
+}
+inline bool operator<(cmValue l, std::nullptr_t) noexcept
+{
+  return l.Compare(cmValue{}) < 0;
+}
+inline bool operator<=(cmValue l, std::nullptr_t) noexcept
+{
+  return l.Compare(cmValue{}) <= 0;
+}
+inline bool operator>(cmValue l, std::nullptr_t) noexcept
+{
+  return l.Compare(cmValue{}) > 0;
+}
+inline bool operator>=(cmValue l, std::nullptr_t) noexcept
+{
+  return l.Compare(cmValue{}) >= 0;
+}
+
+/**
+ * Does a string indicate a true or ON value? This is not the same as ifdef.
+ */
+inline bool cmIsOn(cm::string_view val)
+{
+  return cmValue::IsOn(val);
+}
+inline bool cmIsOn(const char* val)
+{
+  return cmValue::IsOn(val);
+}
+inline bool cmIsOn(cmValue val)
+{
+  return val.IsOn();
+}
+
+/**
+ * Does a string indicate a false or off value ? Note that this is
+ * not the same as !IsOn(...) because there are a number of
+ * ambiguous values such as "/usr/local/bin" a path will result in
+ * IsON and IsOff both returning false. Note that the special path
+ * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true.
+ */
+inline bool cmIsOff(cm::string_view val)
+{
+  return cmValue::IsOff(val);
+}
+inline bool cmIsOff(const char* val)
+{
+  return cmValue::IsOff(val);
+}
+inline bool cmIsOff(cmValue val)
+{
+  return val.IsOff();
+}
+
+/** Return true if value is NOTFOUND or ends in -NOTFOUND.  */
+inline bool cmIsNOTFOUND(cm::string_view val)
+{
+  return cmValue::IsNOTFOUND(val);
+}
+inline bool cmIsNOTFOUND(cmValue val)
+{
+  return val.IsNOTFOUND();
+}
+
+/** Check for non-empty Property/Variable value.  */
+inline bool cmNonempty(cm::string_view val)
+{
+  return !cmValue::IsEmpty(val);
+}
+inline bool cmNonempty(const char* val)
+{
+  return !cmValue::IsEmpty(val);
+}
+inline bool cmNonempty(cmValue val)
+{
+  return !val.IsEmpty();
+}
+
+/**
+ * Does a string indicates that CMake/CPack/CTest internally
+ * forced this value. This is not the same as On, but this
+ * may be considered as "internally switched on".
+ */
+inline bool cmIsInternallyOn(cm::string_view val)
+{
+  return cmValue::IsInternallyOn(val);
+}
+inline bool cmIsInternallyOn(const char* val)
+{
+  return cmValue::IsInternallyOn(val);
+}
+inline bool cmIsInternallyOn(cmValue val)
+{
+  return val.IsInternallyOn();
+}
index 1fe03ab..2b1efba 100644 (file)
@@ -4,10 +4,10 @@
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 
 // cmLibraryCommand
 bool cmVariableRequiresCommand(std::vector<std::string> const& args,
@@ -38,7 +38,7 @@ bool cmVariableRequiresCommand(std::vector<std::string> const& args,
       }
     }
   }
-  cmProp reqVar = status.GetMakefile().GetDefinition(resultVariable);
+  cmValue reqVar = status.GetMakefile().GetDefinition(resultVariable);
   // if reqVar is unset, then set it to requirementsMet
   // if reqVar is set to true, but requirementsMet is false , then
   // set reqVar to false.
index 7c7fbca..fd5402c 100644 (file)
@@ -10,9 +10,9 @@
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmVariableWatch.h"
 #include "cmake.h"
 
@@ -45,7 +45,7 @@ void cmVariableWatchCommandVariableAccessed(const std::string& variable,
 
   std::string stack = *mf->GetProperty("LISTFILE_STACK");
   if (!data->Command.empty()) {
-    cmProp const currentListFile =
+    cmValue const currentListFile =
       mf->GetDefinition("CMAKE_CURRENT_LIST_FILE");
     const auto fakeLineNo =
       std::numeric_limits<decltype(cmListFileArgument::Line)>::max();
index 97cb1bf..d2c49ae 100644 (file)
@@ -6,6 +6,7 @@
 #include <set>
 
 #include <cm/memory>
+#include <cm/optional>
 #include <cm/string_view>
 #include <cm/vector>
 #include <cmext/algorithm>
@@ -437,7 +438,7 @@ void cmVisualStudio10TargetGenerator::Generate()
         this->VerifyNecessaryFiles();
       }
 
-      cmProp vsProjectTypes =
+      cmValue vsProjectTypes =
         this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES");
       if (vsProjectTypes) {
         const char* tagName = "ProjectTypes";
@@ -447,11 +448,11 @@ void cmVisualStudio10TargetGenerator::Generate()
         e1.Element(tagName, *vsProjectTypes);
       }
 
-      cmProp vsProjectName =
+      cmValue vsProjectName =
         this->GeneratorTarget->GetProperty("VS_SCC_PROJECTNAME");
-      cmProp vsLocalPath =
+      cmValue vsLocalPath =
         this->GeneratorTarget->GetProperty("VS_SCC_LOCALPATH");
-      cmProp vsProvider =
+      cmValue vsProvider =
         this->GeneratorTarget->GetProperty("VS_SCC_PROVIDER");
 
       if (vsProjectName && vsLocalPath && vsProvider) {
@@ -459,7 +460,7 @@ void cmVisualStudio10TargetGenerator::Generate()
         e1.Element("SccLocalPath", *vsLocalPath);
         e1.Element("SccProvider", *vsProvider);
 
-        cmProp vsAuxPath =
+        cmValue vsAuxPath =
           this->GeneratorTarget->GetProperty("VS_SCC_AUXPATH");
         if (vsAuxPath) {
           e1.Element("SccAuxPath", *vsAuxPath);
@@ -470,7 +471,7 @@ void cmVisualStudio10TargetGenerator::Generate()
         e1.Element("WinMDAssembly", "true");
       }
 
-      cmProp vsGlobalKeyword =
+      cmValue vsGlobalKeyword =
         this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD");
       if (!vsGlobalKeyword) {
         if (this->GlobalGenerator->TargetsAndroid()) {
@@ -482,63 +483,78 @@ void cmVisualStudio10TargetGenerator::Generate()
         e1.Element("Keyword", *vsGlobalKeyword);
       }
 
-      cmProp vsGlobalRootNamespace =
+      cmValue vsGlobalRootNamespace =
         this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE");
       if (vsGlobalRootNamespace) {
         e1.Element("RootNamespace", *vsGlobalRootNamespace);
       }
 
       e1.Element("Platform", this->Platform);
-      cmProp projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL");
-      if (!projLabel) {
-        projLabel = &this->Name;
-      }
-      e1.Element("ProjectName", *projLabel);
+      cmValue projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL");
+      e1.Element("ProjectName", projLabel ? projLabel : this->Name);
       {
-        cmProp targetFramework =
-          this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK");
+        cm::optional<std::string> targetFramework;
+        cm::optional<std::string> targetFrameworkVersion;
+        cm::optional<std::string> targetFrameworkIdentifier;
+        cm::optional<std::string> targetFrameworkTargetsVersion;
+        if (cmValue tf =
+              this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK")) {
+          targetFramework = *tf;
+        } else if (cmValue vstfVer = this->GeneratorTarget->GetProperty(
+                     "VS_DOTNET_TARGET_FRAMEWORK_VERSION")) {
+          // FIXME: Someday, add a deprecation warning for VS_* property.
+          targetFrameworkVersion = *vstfVer;
+        } else if (cmValue tfVer = this->GeneratorTarget->GetProperty(
+                     "DOTNET_TARGET_FRAMEWORK_VERSION")) {
+          targetFrameworkVersion = *tfVer;
+        } else if (this->ProjectType == csproj) {
+          targetFrameworkVersion =
+            this->GlobalGenerator->GetTargetFrameworkVersion();
+        }
+        if (this->ProjectType == vcxproj &&
+            this->GlobalGenerator->TargetsWindowsCE()) {
+          e1.Element("EnableRedirectPlatform", "true");
+          e1.Element("RedirectPlatformValue", this->Platform);
+        }
+        if (this->ProjectType == csproj) {
+          if (this->GlobalGenerator->TargetsWindowsCE()) {
+            // FIXME: These target VS_TARGET_FRAMEWORK* target properties
+            // are undocumented settings only ever supported for WinCE.
+            // We need a better way to control these in general.
+            if (cmValue tfId = this->GeneratorTarget->GetProperty(
+                  "VS_TARGET_FRAMEWORK_IDENTIFIER")) {
+              targetFrameworkIdentifier = *tfId;
+            }
+            if (cmValue tfTargetsVer = this->GeneratorTarget->GetProperty(
+                  "VS_TARGET_FRAMEWORKS_TARGET_VERSION")) {
+              targetFrameworkTargetsVersion = *tfTargetsVer;
+            }
+          }
+          if (!targetFrameworkIdentifier) {
+            targetFrameworkIdentifier =
+              this->GlobalGenerator->GetTargetFrameworkIdentifier();
+          }
+          if (!targetFrameworkTargetsVersion) {
+            targetFrameworkTargetsVersion =
+              this->GlobalGenerator->GetTargetFrameworkTargetsVersion();
+          }
+        }
         if (targetFramework) {
           if (targetFramework->find(';') != std::string::npos) {
             e1.Element("TargetFrameworks", *targetFramework);
           } else {
             e1.Element("TargetFramework", *targetFramework);
           }
-        } else {
-          // TODO: add deprecation warning for VS_* property?
-          cmProp p = this->GeneratorTarget->GetProperty(
-            "VS_DOTNET_TARGET_FRAMEWORK_VERSION");
-          if (!p) {
-            p = this->GeneratorTarget->GetProperty(
-              "DOTNET_TARGET_FRAMEWORK_VERSION");
-          }
-          const char* targetFrameworkVersion = cmToCStr(p);
-          if (!targetFrameworkVersion && this->ProjectType == csproj &&
-              this->GlobalGenerator->TargetsWindowsCE() &&
-              this->GlobalGenerator->GetVersion() ==
-                cmGlobalVisualStudioGenerator::VS12) {
-            // VS12 .NETCF default to .NET framework 3.9
-            targetFrameworkVersion = "v3.9";
-          }
-          if (targetFrameworkVersion) {
-            e1.Element("TargetFrameworkVersion", targetFrameworkVersion);
-          }
         }
-        if (this->ProjectType == vcxproj &&
-            this->GlobalGenerator->TargetsWindowsCE()) {
-          e1.Element("EnableRedirectPlatform", "true");
-          e1.Element("RedirectPlatformValue", this->Platform);
+        if (targetFrameworkVersion) {
+          e1.Element("TargetFrameworkVersion", *targetFrameworkVersion);
         }
-        if (this->ProjectType == csproj &&
-            this->GlobalGenerator->TargetsWindowsCE()) {
-          cmProp targetFrameworkId = this->GeneratorTarget->GetProperty(
-            "VS_TARGET_FRAMEWORK_IDENTIFIER");
-          e1.Element("TargetFrameworkIdentifier",
-                     targetFrameworkId ? *targetFrameworkId
-                                       : "WindowsEmbeddedCompact");
-          cmProp targetFrameworkVer = this->GeneratorTarget->GetProperty(
-            "VS_TARGET_FRAMEWORKS_TARGET_VERSION");
+        if (targetFrameworkIdentifier) {
+          e1.Element("TargetFrameworkIdentifier", *targetFrameworkIdentifier);
+        }
+        if (targetFrameworkTargetsVersion) {
           e1.Element("TargetFrameworkTargetsVersion",
-                     targetFrameworkVer ? *targetFrameworkVer : "v8.0");
+                     *targetFrameworkTargetsVersion);
         }
         if (!this->GlobalGenerator->GetPlatformToolsetCudaCustomDirString()
                .empty()) {
@@ -574,7 +590,7 @@ void cmVisualStudio10TargetGenerator::Generate()
             globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") {
           continue;
         }
-        cmProp value = this->GeneratorTarget->GetProperty(keyIt);
+        cmValue value = this->GeneratorTarget->GetProperty(keyIt);
         if (!value)
           continue;
         e1.Element(globalKey, *value);
@@ -697,7 +713,7 @@ void cmVisualStudio10TargetGenerator::Generate()
           props = VS10_CSharp_USER_PROPS;
           break;
       }
-      if (cmProp p = this->GeneratorTarget->GetProperty("VS_USER_PROPS")) {
+      if (cmValue p = this->GeneratorTarget->GetProperty("VS_USER_PROPS")) {
         props = *p;
       }
       if (!props.empty()) {
@@ -810,7 +826,7 @@ void cmVisualStudio10TargetGenerator::Generate()
 void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0)
 {
   std::vector<std::string> packageReferences;
-  if (cmProp vsPackageReferences =
+  if (cmValue vsPackageReferences =
         this->GeneratorTarget->GetProperty("VS_PACKAGE_REFERENCES")) {
     cmExpandList(*vsPackageReferences, packageReferences);
   }
@@ -830,7 +846,7 @@ void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0)
 void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0)
 {
   std::vector<std::string> references;
-  if (cmProp vsDotNetReferences =
+  if (cmValue vsDotNetReferences =
         this->GeneratorTarget->GetProperty("VS_DOTNET_REFERENCES")) {
     cmExpandList(*vsDotNetReferences, references);
   }
@@ -889,7 +905,7 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReference(
   e2.Element("ReferenceOutputAssembly", "true");
   if (!hint.empty()) {
     const char* privateReference = "True";
-    if (cmProp value = this->GeneratorTarget->GetProperty(
+    if (cmValue value = this->GeneratorTarget->GetProperty(
           "VS_DOTNET_REFERENCES_COPY_LOCAL")) {
       if (cmIsOff(*value)) {
         privateReference = "False";
@@ -903,7 +919,7 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReference(
 
 void cmVisualStudio10TargetGenerator::WriteImports(Elem& e0)
 {
-  cmProp imports =
+  cmValue imports =
     this->GeneratorTarget->Target->GetProperty("VS_PROJECT_IMPORT");
   if (imports) {
     std::vector<std::string> argsSplit = cmExpandedList(*imports, false);
@@ -1007,7 +1023,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0)
           ".Designer.cs";
         if (cmsys::SystemTools::FileExists(designerResource)) {
           std::string generator = "PublicResXFileCodeGenerator";
-          if (cmProp g = oi->GetProperty("VS_RESOURCE_GENERATOR")) {
+          if (cmValue g = oi->GetProperty("VS_RESOURCE_GENERATOR")) {
             generator = *g;
           }
           if (!generator.empty()) {
@@ -1031,7 +1047,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0)
             cm::string_view tagName =
               cm::string_view(p).substr(propNamePrefix.length());
             if (!tagName.empty()) {
-              cmProp value = props.GetPropertyValue(p);
+              cmValue value = props.GetPropertyValue(p);
               if (cmNonempty(value)) {
                 e2.Element(tagName, *value);
               }
@@ -1050,7 +1066,7 @@ void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup(Elem& e0)
     for (cmSourceFile const* oi : this->XamlObjs) {
       std::string obj = oi->GetFullPath();
       std::string xamlType;
-      cmProp xamlTypeProperty = oi->GetProperty("VS_XAML_TYPE");
+      cmValue xamlTypeProperty = oi->GetProperty("VS_XAML_TYPE");
       if (xamlTypeProperty) {
         xamlType = *xamlTypeProperty;
       } else {
@@ -1104,7 +1120,7 @@ void cmVisualStudio10TargetGenerator::WriteTargetsFileReferences(Elem& e1)
 void cmVisualStudio10TargetGenerator::WriteWinRTReferences(Elem& e0)
 {
   std::vector<std::string> references;
-  if (cmProp vsWinRTReferences =
+  if (cmValue vsWinRTReferences =
         this->GeneratorTarget->GetProperty("VS_WINRT_REFERENCES")) {
     cmExpandList(*vsWinRTReferences, references);
   }
@@ -1147,7 +1163,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues(Elem& e0)
 
     if (this->ProjectType != csproj) {
       std::string configType;
-      if (cmProp vsConfigurationType =
+      if (cmValue vsConfigurationType =
             this->GeneratorTarget->GetProperty("VS_CONFIGURATION_TYPE")) {
         configType = cmGeneratorExpression::Evaluate(*vsConfigurationType,
                                                      this->LocalGenerator, c);
@@ -1209,9 +1225,9 @@ void cmVisualStudio10TargetGenerator::WriteCEDebugProjectConfigurationValues(
   if (!this->GlobalGenerator->TargetsWindowsCE()) {
     return;
   }
-  cmProp additionalFiles =
+  cmValue additionalFiles =
     this->GeneratorTarget->GetProperty("DEPLOYMENT_ADDITIONAL_FILES");
-  cmProp remoteDirectory =
+  cmValue remoteDirectory =
     this->GeneratorTarget->GetProperty("DEPLOYMENT_REMOTE_DIRECTORY");
   if (!(additionalFiles || remoteDirectory)) {
     return;
@@ -1233,7 +1249,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
   Elem& e1, std::string const& config)
 {
   cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
-  cmProp mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG");
+  cmValue mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG");
   if (mfcFlag) {
     std::string const mfcFlagValue =
       cmGeneratorExpression::Evaluate(*mfcFlag, this->LocalGenerator, config);
@@ -1263,7 +1279,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
   } else {
     e1.Element("CharacterSet", "MultiByte");
   }
-  if (cmProp projectToolsetOverride =
+  if (cmValue projectToolsetOverride =
         this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) {
     e1.Element("PlatformToolset", *projectToolsetOverride);
   } else if (const char* toolset = gg->GetPlatformToolset()) {
@@ -1309,7 +1325,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged(
     o.RemoveFlag("Platform");
   }
 
-  if (cmProp projectToolsetOverride =
+  if (cmValue projectToolsetOverride =
         this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) {
     e1.Element("PlatformToolset", *projectToolsetOverride);
   } else if (const char* toolset = gg->GetPlatformToolset()) {
@@ -1320,7 +1336,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged(
     cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX");
   std::string assemblyName = this->GeneratorTarget->GetOutputName(
     config, cmStateEnums::RuntimeBinaryArtifact);
-  if (cmProp postfix = this->GeneratorTarget->GetProperty(postfixName)) {
+  if (cmValue postfix = this->GeneratorTarget->GetProperty(postfixName)) {
     assemblyName += *postfix;
   }
   e1.Element("AssemblyName", assemblyName);
@@ -1341,18 +1357,18 @@ void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues(
   cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
   const char* toolset = gg->GetPlatformToolset();
   e1.Element("NdkToolchainVersion", toolset ? toolset : "Default");
-  if (cmProp minApi = this->GeneratorTarget->GetProperty("ANDROID_API_MIN")) {
+  if (cmValue minApi = this->GeneratorTarget->GetProperty("ANDROID_API_MIN")) {
     e1.Element("AndroidMinAPI", "android-" + *minApi);
   }
-  if (cmProp api = this->GeneratorTarget->GetProperty("ANDROID_API")) {
+  if (cmValue api = this->GeneratorTarget->GetProperty("ANDROID_API")) {
     e1.Element("AndroidTargetAPI", "android-" + *api);
   }
 
-  if (cmProp cpuArch = this->GeneratorTarget->GetProperty("ANDROID_ARCH")) {
+  if (cmValue cpuArch = this->GeneratorTarget->GetProperty("ANDROID_ARCH")) {
     e1.Element("AndroidArch", *cpuArch);
   }
 
-  if (cmProp stlType =
+  if (cmValue stlType =
         this->GeneratorTarget->GetProperty("ANDROID_STL_TYPE")) {
     e1.Element("AndroidStlType", *stlType);
   }
@@ -1362,13 +1378,13 @@ void cmVisualStudio10TargetGenerator::WriteAndroidConfigurationValues(
   Elem& e1, std::string const&)
 {
   cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
-  if (cmProp projectToolsetOverride =
+  if (cmValue projectToolsetOverride =
         this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) {
     e1.Element("PlatformToolset", *projectToolsetOverride);
   } else if (const char* toolset = gg->GetPlatformToolset()) {
     e1.Element("PlatformToolset", toolset);
   }
-  if (cmProp stlType =
+  if (cmValue stlType =
         this->GeneratorTarget->GetProperty("ANDROID_STL_TYPE")) {
     if (*stlType != "none") {
       e1.Element("UseOfStl", *stlType);
@@ -1472,7 +1488,10 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule(
     cmCustomCommandGenerator ccg(command, c, lg, true);
     std::string comment = lg->ConstructComment(ccg);
     comment = cmVS10EscapeComment(comment);
-    std::string script = lg->ConstructScript(ccg);
+    cmLocalVisualStudioGenerator::IsManaged isManaged = (this->Managed)
+      ? cmLocalVisualStudioGenerator::managed
+      : cmLocalVisualStudioGenerator::unmanaged;
+    std::string script = lg->ConstructScript(ccg, isManaged);
     bool symbolic = false;
     // input files for custom command
     std::stringstream additional_inputs;
@@ -1803,8 +1822,8 @@ void cmVisualStudio10TargetGenerator::WriteGroupSources(
   }
 }
 
-void cmVisualStudio10TargetGenerator::WriteHeaderSource(Elem& e1,
-                                                        cmSourceFile const* sf)
+void cmVisualStudio10TargetGenerator::WriteHeaderSource(
+  Elem& e1, cmSourceFile const* sf, ConfigToSettings const& toolSettings)
 {
   std::string const& fileName = sf->GetFullPath();
   Elem e2(e1, "ClInclude");
@@ -1815,6 +1834,7 @@ void cmVisualStudio10TargetGenerator::WriteHeaderSource(Elem& e1,
     e2.Element("DependentUpon",
                fileName.substr(0, fileName.find_last_of(".")));
   }
+  this->FinishWritingSource(e2, toolSettings);
 }
 
 void cmVisualStudio10TargetGenerator::ParseSettingsProperty(
@@ -1871,8 +1891,8 @@ bool cmVisualStudio10TargetGenerator::PropertyIsSameInAllConfigs(
   return true;
 }
 
-void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
-                                                       cmSourceFile const* sf)
+void cmVisualStudio10TargetGenerator::WriteExtraSource(
+  Elem& e1, cmSourceFile const* sf, ConfigToSettings& toolSettings)
 {
   bool toolHasSettings = false;
   const char* tool = "None";
@@ -1883,10 +1903,6 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
   std::string copyToOutDir;
   std::string includeInVsix;
   std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
-  ConfigToSettings toolSettings;
-  for (const auto& config : this->Configurations) {
-    toolSettings[config];
-  }
 
   if (this->ProjectType == csproj && !this->InSourceBuild) {
     toolHasSettings = true;
@@ -1894,37 +1910,37 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
   if (ext == "hlsl") {
     tool = "FXCompile";
     // Figure out the type of shader compiler to use.
-    if (cmProp st = sf->GetProperty("VS_SHADER_TYPE")) {
+    if (cmValue st = sf->GetProperty("VS_SHADER_TYPE")) {
       for (const std::string& config : this->Configurations) {
         toolSettings[config]["ShaderType"] = *st;
       }
     }
     // Figure out which entry point to use if any
-    if (cmProp se = sf->GetProperty("VS_SHADER_ENTRYPOINT")) {
+    if (cmValue se = sf->GetProperty("VS_SHADER_ENTRYPOINT")) {
       for (const std::string& config : this->Configurations) {
         toolSettings[config]["EntryPointName"] = *se;
       }
     }
     // Figure out which shader model to use if any
-    if (cmProp sm = sf->GetProperty("VS_SHADER_MODEL")) {
+    if (cmValue sm = sf->GetProperty("VS_SHADER_MODEL")) {
       for (const std::string& config : this->Configurations) {
         toolSettings[config]["ShaderModel"] = *sm;
       }
     }
     // Figure out which output header file to use if any
-    if (cmProp ohf = sf->GetProperty("VS_SHADER_OUTPUT_HEADER_FILE")) {
+    if (cmValue ohf = sf->GetProperty("VS_SHADER_OUTPUT_HEADER_FILE")) {
       for (const std::string& config : this->Configurations) {
         toolSettings[config]["HeaderFileOutput"] = *ohf;
       }
     }
     // Figure out which variable name to use if any
-    if (cmProp vn = sf->GetProperty("VS_SHADER_VARIABLE_NAME")) {
+    if (cmValue vn = sf->GetProperty("VS_SHADER_VARIABLE_NAME")) {
       for (const std::string& config : this->Configurations) {
         toolSettings[config]["VariableName"] = *vn;
       }
     }
     // Figure out if there's any additional flags to use
-    if (cmProp saf = sf->GetProperty("VS_SHADER_FLAGS")) {
+    if (cmValue saf = sf->GetProperty("VS_SHADER_FLAGS")) {
       cmGeneratorExpression ge;
       std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*saf);
 
@@ -1937,7 +1953,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
       }
     }
     // Figure out if debug information should be generated
-    if (cmProp sed = sf->GetProperty("VS_SHADER_ENABLE_DEBUG")) {
+    if (cmValue sed = sf->GetProperty("VS_SHADER_ENABLE_DEBUG")) {
       cmGeneratorExpression ge;
       std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*sed);
 
@@ -1951,7 +1967,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
       }
     }
     // Figure out if optimizations should be disabled
-    if (cmProp sdo = sf->GetProperty("VS_SHADER_DISABLE_OPTIMIZATIONS")) {
+    if (cmValue sdo = sf->GetProperty("VS_SHADER_DISABLE_OPTIMIZATIONS")) {
       cmGeneratorExpression ge;
       std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*sdo);
 
@@ -1964,7 +1980,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
         }
       }
     }
-    if (cmProp sofn = sf->GetProperty("VS_SHADER_OBJECT_FILE_NAME")) {
+    if (cmValue sofn = sf->GetProperty("VS_SHADER_OBJECT_FILE_NAME")) {
       for (const std::string& config : this->Configurations) {
         toolSettings[config]["ObjectFileOutput"] = *sofn;
       }
@@ -1987,7 +2003,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
   } else if (ext == "vsixmanifest") {
     subType = "Designer";
   }
-  if (cmProp c = sf->GetProperty("VS_COPY_TO_OUT_DIR")) {
+  if (cmValue c = sf->GetProperty("VS_COPY_TO_OUT_DIR")) {
     tool = "Content";
     copyToOutDir = *c;
     toolHasSettings = true;
@@ -2016,7 +2032,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
     }
   }
 
-  cmProp toolOverride = sf->GetProperty("VS_TOOL_OVERRIDE");
+  cmValue toolOverride = sf->GetProperty("VS_TOOL_OVERRIDE");
   if (cmNonempty(toolOverride)) {
     tool = toolOverride->c_str();
   }
@@ -2025,12 +2041,12 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
   std::string deployLocation;
   if (this->GlobalGenerator->TargetsWindowsPhone() ||
       this->GlobalGenerator->TargetsWindowsStore()) {
-    cmProp content = sf->GetProperty("VS_DEPLOYMENT_CONTENT");
+    cmValue content = sf->GetProperty("VS_DEPLOYMENT_CONTENT");
     if (cmNonempty(content)) {
       toolHasSettings = true;
       deployContent = *content;
 
-      cmProp location = sf->GetProperty("VS_DEPLOYMENT_LOCATION");
+      cmValue location = sf->GetProperty("VS_DEPLOYMENT_LOCATION");
       if (cmNonempty(location)) {
         deployLocation = *location;
       }
@@ -2038,7 +2054,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
   }
 
   if (ParsedToolTargetSettings.find(tool) == ParsedToolTargetSettings.end()) {
-    cmProp toolTargetProperty = this->GeneratorTarget->Target->GetProperty(
+    cmValue toolTargetProperty = this->GeneratorTarget->Target->GetProperty(
       "VS_SOURCE_SETTINGS_" + std::string(tool));
     ConfigToSettings toolTargetSettings;
     if (toolTargetProperty) {
@@ -2054,10 +2070,6 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
     }
   }
 
-  if (cmProp p = sf->GetProperty("VS_SETTINGS")) {
-    ParseSettingsProperty(*p, toolSettings);
-  }
-
   if (!toolSettings.empty()) {
     toolHasSettings = true;
   }
@@ -2067,27 +2079,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
   if (toolHasSettings) {
     e2.SetHasElements();
 
-    std::vector<std::string> writtenSettings;
-    for (const auto& configSettings : toolSettings) {
-      for (const auto& setting : configSettings.second) {
-
-        if (std::find(writtenSettings.begin(), writtenSettings.end(),
-                      setting.first) != writtenSettings.end()) {
-          continue;
-        }
-
-        if (PropertyIsSameInAllConfigs(toolSettings, setting.first)) {
-          e2.Element(setting.first, setting.second);
-          writtenSettings.push_back(setting.first);
-        } else {
-          e2.WritePlatformConfigTag(setting.first,
-                                    "'$(Configuration)|$(Platform)'=='" +
-                                      configSettings.first + "|" +
-                                      this->Platform + "'",
-                                    setting.second);
-        }
-      }
-    }
+    this->FinishWritingSource(e2, toolSettings);
 
     if (!deployContent.empty()) {
       cmGeneratorExpression ge;
@@ -2224,6 +2216,15 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
       // Skip explicit reference to CMakeLists.txt source.
       continue;
     }
+
+    ConfigToSettings toolSettings;
+    for (const auto& config : this->Configurations) {
+      toolSettings[config];
+    }
+    if (cmValue p = si.Source->GetProperty("VS_SETTINGS")) {
+      ParseSettingsProperty(*p, toolSettings);
+    }
+
     const char* tool = nullptr;
     switch (si.Kind) {
       case cmGeneratorTarget::SourceKindAppManifest:
@@ -2251,10 +2252,10 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
         }
         break;
       case cmGeneratorTarget::SourceKindExtra:
-        this->WriteExtraSource(e1, si.Source);
+        this->WriteExtraSource(e1, si.Source, toolSettings);
         break;
       case cmGeneratorTarget::SourceKindHeader:
-        this->WriteHeaderSource(e1, si.Source);
+        this->WriteHeaderSource(e1, si.Source, toolSettings);
         break;
       case cmGeneratorTarget::SourceKindIDL:
         tool = "Midl";
@@ -2364,6 +2365,8 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
       if (!isCSharp && !exclude_configs.empty()) {
         this->WriteExcludeFromBuild(e2, exclude_configs);
       }
+
+      this->FinishWritingSource(e2, toolSettings);
     }
   }
 
@@ -2372,6 +2375,32 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
   }
 }
 
+void cmVisualStudio10TargetGenerator::FinishWritingSource(
+  Elem& e2, ConfigToSettings const& toolSettings)
+{
+  std::vector<std::string> writtenSettings;
+  for (const auto& configSettings : toolSettings) {
+    for (const auto& setting : configSettings.second) {
+
+      if (std::find(writtenSettings.begin(), writtenSettings.end(),
+                    setting.first) != writtenSettings.end()) {
+        continue;
+      }
+
+      if (PropertyIsSameInAllConfigs(toolSettings, setting.first)) {
+        e2.Element(setting.first, setting.second);
+        writtenSettings.push_back(setting.first);
+      } else {
+        e2.WritePlatformConfigTag(setting.first,
+                                  "'$(Configuration)|$(Platform)'=='" +
+                                    configSettings.first + "|" +
+                                    this->Platform + "'",
+                                  setting.second);
+      }
+    }
+  }
+}
+
 void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
   Elem& e2, cmSourceFile const* source)
 {
@@ -2389,22 +2418,22 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
   bool configDependentDefines = false;
   std::string includes;
   bool configDependentIncludes = false;
-  if (cmProp cflags = sf.GetProperty("COMPILE_FLAGS")) {
+  if (cmValue cflags = sf.GetProperty("COMPILE_FLAGS")) {
     configDependentFlags =
       cmGeneratorExpression::Find(*cflags) != std::string::npos;
     flags += *cflags;
   }
-  if (cmProp coptions = sf.GetProperty("COMPILE_OPTIONS")) {
+  if (cmValue coptions = sf.GetProperty("COMPILE_OPTIONS")) {
     configDependentOptions =
       cmGeneratorExpression::Find(*coptions) != std::string::npos;
     options += *coptions;
   }
-  if (cmProp cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) {
+  if (cmValue cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) {
     configDependentDefines =
       cmGeneratorExpression::Find(*cdefs) != std::string::npos;
     defines += *cdefs;
   }
-  if (cmProp cincludes = sf.GetProperty("INCLUDE_DIRECTORIES")) {
+  if (cmValue cincludes = sf.GetProperty("INCLUDE_DIRECTORIES")) {
     configDependentIncludes =
       cmGeneratorExpression::Find(*cincludes) != std::string::npos;
     includes += *cincludes;
@@ -2442,7 +2471,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
     std::string configUpper = cmSystemTools::UpperCase(config);
     std::string configDefines = defines;
     std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", configUpper);
-    if (cmProp ccdefs = sf.GetProperty(defPropName)) {
+    if (cmValue ccdefs = sf.GetProperty(defPropName)) {
       if (!configDefines.empty()) {
         configDefines += ";";
       }
@@ -2618,7 +2647,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions(
     const std::string cond = this->CalcCondition(config);
 
     if (ttype <= cmStateEnums::UTILITY) {
-      if (cmProp workingDir = this->GeneratorTarget->GetProperty(
+      if (cmValue workingDir = this->GeneratorTarget->GetProperty(
             "VS_DEBUGGER_WORKING_DIRECTORY")) {
         std::string genWorkingDir = cmGeneratorExpression::Evaluate(
           *workingDir, this->LocalGenerator, config);
@@ -2626,7 +2655,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions(
                                   genWorkingDir);
       }
 
-      if (cmProp environment =
+      if (cmValue environment =
             this->GeneratorTarget->GetProperty("VS_DEBUGGER_ENVIRONMENT")) {
         std::string genEnvironment = cmGeneratorExpression::Evaluate(
           *environment, this->LocalGenerator, config);
@@ -2634,7 +2663,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions(
                                   genEnvironment);
       }
 
-      if (cmProp debuggerCommand =
+      if (cmValue debuggerCommand =
             this->GeneratorTarget->GetProperty("VS_DEBUGGER_COMMAND")) {
         std::string genDebuggerCommand = cmGeneratorExpression::Evaluate(
           *debuggerCommand, this->LocalGenerator, config);
@@ -2642,7 +2671,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions(
                                   genDebuggerCommand);
       }
 
-      if (cmProp commandArguments = this->GeneratorTarget->GetProperty(
+      if (cmValue commandArguments = this->GeneratorTarget->GetProperty(
             "VS_DEBUGGER_COMMAND_ARGUMENTS")) {
         std::string genCommandArguments = cmGeneratorExpression::Evaluate(
           *commandArguments, this->LocalGenerator, config);
@@ -2674,40 +2703,40 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions(
 
       e1.WritePlatformConfigTag("IntDir", cond, intermediateDir);
 
-      if (cmProp sdkExecutableDirectories = this->Makefile->GetDefinition(
+      if (cmValue sdkExecutableDirectories = this->Makefile->GetDefinition(
             "CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES")) {
         e1.WritePlatformConfigTag("ExecutablePath", cond,
                                   *sdkExecutableDirectories);
       }
 
-      if (cmProp sdkIncludeDirectories = this->Makefile->GetDefinition(
+      if (cmValue sdkIncludeDirectories = this->Makefile->GetDefinition(
             "CMAKE_VS_SDK_INCLUDE_DIRECTORIES")) {
         e1.WritePlatformConfigTag("IncludePath", cond, *sdkIncludeDirectories);
       }
 
-      if (cmProp sdkReferenceDirectories = this->Makefile->GetDefinition(
+      if (cmValue sdkReferenceDirectories = this->Makefile->GetDefinition(
             "CMAKE_VS_SDK_REFERENCE_DIRECTORIES")) {
         e1.WritePlatformConfigTag("ReferencePath", cond,
                                   *sdkReferenceDirectories);
       }
 
-      if (cmProp sdkLibraryDirectories = this->Makefile->GetDefinition(
+      if (cmValue sdkLibraryDirectories = this->Makefile->GetDefinition(
             "CMAKE_VS_SDK_LIBRARY_DIRECTORIES")) {
         e1.WritePlatformConfigTag("LibraryPath", cond, *sdkLibraryDirectories);
       }
 
-      if (cmProp sdkLibraryWDirectories = this->Makefile->GetDefinition(
+      if (cmValue sdkLibraryWDirectories = this->Makefile->GetDefinition(
             "CMAKE_VS_SDK_LIBRARY_WINRT_DIRECTORIES")) {
         e1.WritePlatformConfigTag("LibraryWPath", cond,
                                   *sdkLibraryWDirectories);
       }
 
-      if (cmProp sdkSourceDirectories =
+      if (cmValue sdkSourceDirectories =
             this->Makefile->GetDefinition("CMAKE_VS_SDK_SOURCE_DIRECTORIES")) {
         e1.WritePlatformConfigTag("SourcePath", cond, *sdkSourceDirectories);
       }
 
-      if (cmProp sdkExcludeDirectories = this->Makefile->GetDefinition(
+      if (cmValue sdkExcludeDirectories = this->Makefile->GetDefinition(
             "CMAKE_VS_SDK_EXCLUDE_DIRECTORIES")) {
         e1.WritePlatformConfigTag("ExcludePath", cond, *sdkExcludeDirectories);
       }
@@ -2905,7 +2934,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
         this->Makefile->IssueMessage(MessageType::WARNING, message);
       }
     }
-    if (cmProp clr =
+    if (cmValue clr =
           this->GeneratorTarget->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
       std::string clrString = *clr;
       if (!clrString.empty()) {
@@ -3048,7 +3077,7 @@ void cmVisualStudio10TargetGenerator::WriteClOptions(
   oh.OutputPreprocessorDefinitions(this->LangForClCompile);
 
   if (this->NsightTegra) {
-    if (cmProp processMax =
+    if (cmValue processMax =
           this->GeneratorTarget->GetProperty("ANDROID_PROCESS_MAX")) {
       e2.Element("ProcessMax", *processMax);
     }
@@ -3547,8 +3576,6 @@ void cmVisualStudio10TargetGenerator::WriteNasmOptions(
   }
   Elem e2(e1, "NASM");
 
-  std::vector<std::string> includes =
-    this->GetIncludes(configName, "ASM_NASM");
   OptionsHelper nasmOptions(*(this->NasmOptions[configName]), e2);
   nasmOptions.OutputAdditionalIncludeDirectories("ASM_NASM");
   nasmOptions.OutputFlagMap();
@@ -3608,7 +3635,7 @@ void cmVisualStudio10TargetGenerator::WriteManifestOptions(
   std::vector<cmSourceFile const*> manifest_srcs;
   this->GeneratorTarget->GetManifests(manifest_srcs, config);
 
-  cmProp dpiAware = this->GeneratorTarget->GetProperty("VS_DPI_AWARE");
+  cmValue dpiAware = this->GeneratorTarget->GetProperty("VS_DPI_AWARE");
 
   if (!manifest_srcs.empty() || dpiAware) {
     Elem e2(e1, "Manifest");
@@ -3669,24 +3696,24 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions(
     e2.Element("EnableProGuard", "true");
   }
 
-  if (cmProp proGuardConfigLocation =
+  if (cmValue proGuardConfigLocation =
         this->GeneratorTarget->GetProperty("ANDROID_PROGUARD_CONFIG_PATH")) {
     e2.Element("ProGuardConfigLocation", *proGuardConfigLocation);
   }
 
-  if (cmProp securePropertiesLocation =
+  if (cmValue securePropertiesLocation =
         this->GeneratorTarget->GetProperty("ANDROID_SECURE_PROPS_PATH")) {
     e2.Element("SecurePropertiesLocation", *securePropertiesLocation);
   }
 
-  if (cmProp nativeLibDirectoriesExpression =
+  if (cmValue nativeLibDirectoriesExpression =
         this->GeneratorTarget->GetProperty("ANDROID_NATIVE_LIB_DIRECTORIES")) {
     std::string nativeLibDirs = cmGeneratorExpression::Evaluate(
       *nativeLibDirectoriesExpression, this->LocalGenerator, configName);
     e2.Element("NativeLibDirectories", nativeLibDirs);
   }
 
-  if (cmProp nativeLibDependenciesExpression =
+  if (cmValue nativeLibDependenciesExpression =
         this->GeneratorTarget->GetProperty(
           "ANDROID_NATIVE_LIB_DEPENDENCIES")) {
     std::string nativeLibDeps = cmGeneratorExpression::Evaluate(
@@ -3694,24 +3721,24 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions(
     e2.Element("NativeLibDependencies", nativeLibDeps);
   }
 
-  if (cmProp javaSourceDir =
+  if (cmValue javaSourceDir =
         this->GeneratorTarget->GetProperty("ANDROID_JAVA_SOURCE_DIR")) {
     e2.Element("JavaSourceDir", *javaSourceDir);
   }
 
-  if (cmProp jarDirectoriesExpression =
+  if (cmValue jarDirectoriesExpression =
         this->GeneratorTarget->GetProperty("ANDROID_JAR_DIRECTORIES")) {
     std::string jarDirectories = cmGeneratorExpression::Evaluate(
       *jarDirectoriesExpression, this->LocalGenerator, configName);
     e2.Element("JarDirectories", jarDirectories);
   }
 
-  if (cmProp jarDeps =
+  if (cmValue jarDeps =
         this->GeneratorTarget->GetProperty("ANDROID_JAR_DEPENDENCIES")) {
     e2.Element("JarDependencies", *jarDeps);
   }
 
-  if (cmProp assetsDirectories =
+  if (cmValue assetsDirectories =
         this->GeneratorTarget->GetProperty("ANDROID_ASSETS_DIRECTORIES")) {
     e2.Element("AssetsDirectories", *assetsDirectories);
   }
@@ -3722,7 +3749,7 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions(
     e2.Element("AndroidManifestLocation", manifest_xml);
   }
 
-  if (cmProp antAdditionalOptions =
+  if (cmValue antAdditionalOptions =
         this->GeneratorTarget->GetProperty("ANDROID_ANT_ADDITIONAL_OPTIONS")) {
     e2.Element("AdditionalOptions",
                *antAdditionalOptions + " %(AdditionalOptions)");
@@ -3777,13 +3804,13 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
   std::string linkFlagVar = linkFlagVarBase + "_" + CONFIG;
   flags += " ";
   flags += this->Makefile->GetRequiredDefinition(linkFlagVar);
-  cmProp targetLinkFlags = this->GeneratorTarget->GetProperty("LINK_FLAGS");
+  cmValue targetLinkFlags = this->GeneratorTarget->GetProperty("LINK_FLAGS");
   if (targetLinkFlags) {
     flags += " ";
     flags += *targetLinkFlags;
   }
   std::string flagsProp = cmStrCat("LINK_FLAGS_", CONFIG);
-  if (cmProp flagsConfig = this->GeneratorTarget->GetProperty(flagsProp)) {
+  if (cmValue flagsConfig = this->GeneratorTarget->GetProperty(flagsProp)) {
     flags += " ";
     flags += *flagsConfig;
   }
@@ -3864,7 +3891,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
       };
     }
 
-    if (cmProp stackVal = this->Makefile->GetDefinition(
+    if (cmValue stackVal = this->Makefile->GetDefinition(
           "CMAKE_" + linkLanguage + "_STACK_SIZE")) {
       linkOptions.AddFlag("StackReserveSize", *stackVal);
     }
@@ -4214,7 +4241,10 @@ void cmVisualStudio10TargetGenerator::WriteEvent(
       comment += lg->ConstructComment(ccg);
       script += pre;
       pre = "\n";
-      script += lg->ConstructScript(ccg);
+      cmLocalVisualStudioGenerator::IsManaged isManaged = (this->Managed)
+        ? cmLocalVisualStudioGenerator::managed
+        : cmLocalVisualStudioGenerator::unmanaged;
+      script += lg->ConstructScript(ccg, isManaged);
 
       stdPipesUTF8 = stdPipesUTF8 || cc.GetStdPipesUTF8();
     }
@@ -4262,7 +4292,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences(Elem& e0)
     cmLocalGenerator* lg = dt->GetLocalGenerator();
     std::string name = dt->GetName();
     std::string path;
-    if (cmProp p = dt->GetProperty("EXTERNAL_MSPROJECT")) {
+    if (cmValue p = dt->GetProperty("EXTERNAL_MSPROJECT")) {
       path = *p;
     } else {
       path = cmStrCat(lg->GetCurrentBinaryDirectory(), '/', dt->GetName(),
@@ -4292,13 +4322,13 @@ void cmVisualStudio10TargetGenerator::WritePlatformExtensions(Elem& e1)
   // This only applies to Windows 10 apps
   if (this->GlobalGenerator->TargetsWindowsStore() &&
       cmHasLiteralPrefix(this->GlobalGenerator->GetSystemVersion(), "10.0")) {
-    cmProp desktopExtensionsVersion =
+    cmValue desktopExtensionsVersion =
       this->GeneratorTarget->GetProperty("VS_DESKTOP_EXTENSIONS_VERSION");
     if (desktopExtensionsVersion) {
       this->WriteSinglePlatformExtension(e1, "WindowsDesktop",
                                          *desktopExtensionsVersion);
     }
-    cmProp mobileExtensionsVersion =
+    cmValue mobileExtensionsVersion =
       this->GeneratorTarget->GetProperty("VS_MOBILE_EXTENSIONS_VERSION");
     if (mobileExtensionsVersion) {
       this->WriteSinglePlatformExtension(e1, "WindowsMobile",
@@ -4327,7 +4357,7 @@ void cmVisualStudio10TargetGenerator::WriteSDKReferences(Elem& e0)
 {
   std::vector<std::string> sdkReferences;
   std::unique_ptr<Elem> spe1;
-  if (cmProp vsSDKReferences =
+  if (cmValue vsSDKReferences =
         this->GeneratorTarget->GetProperty("VS_SDK_REFERENCES")) {
     cmExpandList(*vsSDKReferences, sdkReferences);
     spe1 = cm::make_unique<Elem>(e0, "ItemGroup");
@@ -4339,11 +4369,11 @@ void cmVisualStudio10TargetGenerator::WriteSDKReferences(Elem& e0)
   // This only applies to Windows 10 apps
   if (this->GlobalGenerator->TargetsWindowsStore() &&
       cmHasLiteralPrefix(this->GlobalGenerator->GetSystemVersion(), "10.0")) {
-    cmProp desktopExtensionsVersion =
+    cmValue desktopExtensionsVersion =
       this->GeneratorTarget->GetProperty("VS_DESKTOP_EXTENSIONS_VERSION");
-    cmProp mobileExtensionsVersion =
+    cmValue mobileExtensionsVersion =
       this->GeneratorTarget->GetProperty("VS_MOBILE_EXTENSIONS_VERSION");
-    cmProp iotExtensionsVersion =
+    cmValue iotExtensionsVersion =
       this->GeneratorTarget->GetProperty("VS_IOT_EXTENSIONS_VERSION");
 
     if (desktopExtensionsVersion || mobileExtensionsVersion ||
@@ -4553,7 +4583,7 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1)
   if (!targetPlatformVersion.empty()) {
     e1.Element("WindowsTargetPlatformVersion", targetPlatformVersion);
   }
-  cmProp targetPlatformMinVersion = this->GeneratorTarget->GetProperty(
+  cmValue targetPlatformMinVersion = this->GeneratorTarget->GetProperty(
     "VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION");
   if (targetPlatformMinVersion) {
     e1.Element("WindowsTargetPlatformMinVersion", *targetPlatformMinVersion);
@@ -5049,7 +5079,7 @@ void cmVisualStudio10TargetGenerator::GetCSharpSourceProperties(
       if (cmHasPrefix(p, propNamePrefix)) {
         std::string tagName = p.substr(propNamePrefix.length());
         if (!tagName.empty()) {
-          cmProp val = props.GetPropertyValue(p);
+          cmValue val = props.GetPropertyValue(p);
           if (cmNonempty(val)) {
             tags[tagName] = *val;
           } else {
@@ -5101,7 +5131,7 @@ std::string cmVisualStudio10TargetGenerator::GetCSharpSourceLink(
   } else if (!cmHasSuffix(fullFileName, ".cs") &&
              cmHasPrefix(fullFileName, binDir)) {
     link = fullFileName.substr(binDir.length() + 1);
-  } else if (cmProp l = source->GetProperty("VS_CSHARP_Link")) {
+  } else if (cmValue l = source->GetProperty("VS_CSHARP_Link")) {
     link = *l;
   }
 
index 55c5444..a5ce5e5 100644 (file)
@@ -58,6 +58,10 @@ private:
   struct Elem;
   struct OptionsHelper;
 
+  using ConfigToSettings =
+    std::unordered_map<std::string,
+                       std::unordered_map<std::string, std::string>>;
+
   std::string ConvertPath(std::string const& path, bool forceRelative);
   std::string CalcCondition(const std::string& config) const;
   void WriteProjectConfigurations(Elem& e0);
@@ -66,12 +70,15 @@ private:
   void WriteCEDebugProjectConfigurationValues(Elem& e0);
   void WriteMSToolConfigurationValuesManaged(Elem& e1,
                                              std::string const& config);
-  void WriteHeaderSource(Elem& e1, cmSourceFile const* sf);
-  void WriteExtraSource(Elem& e1, cmSourceFile const* sf);
+  void WriteHeaderSource(Elem& e1, cmSourceFile const* sf,
+                         ConfigToSettings const& toolSettings);
+  void WriteExtraSource(Elem& e1, cmSourceFile const* sf,
+                        ConfigToSettings& toolSettings);
   void WriteNsightTegraConfigurationValues(Elem& e1,
                                            std::string const& config);
   void WriteAndroidConfigurationValues(Elem& e1, std::string const& config);
   void WriteSource(Elem& e2, cmSourceFile const* sf);
+  void FinishWritingSource(Elem& e2, ConfigToSettings const& toolSettings);
   void WriteExcludeFromBuild(Elem& e2,
                              std::vector<size_t> const& exclude_configs);
   void WriteAllSources(Elem& e0);
@@ -252,9 +259,6 @@ private:
   void ClassifyAllConfigSources();
   void ClassifyAllConfigSource(cmGeneratorTarget::AllConfigSource const& acs);
 
-  using ConfigToSettings =
-    std::unordered_map<std::string,
-                       std::unordered_map<std::string, std::string>>;
   std::unordered_map<std::string, ConfigToSettings> ParsedToolTargetSettings;
   bool PropertyIsSameInAllConfigs(const ConfigToSettings& toolSettings,
                                   const std::string& propName);
index 327c1c7..b8297ce 100644 (file)
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmOutputConverter.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
 
 class cmWhileFunctionBlocker : public cmFunctionBlocker
 {
 public:
-  cmWhileFunctionBlocker(cmMakefile* mf);
+  cmWhileFunctionBlocker(cmMakefile* mf, std::vector<cmListFileArgument> args);
   ~cmWhileFunctionBlocker() override;
 
   cm::string_view StartCommandName() const override { return "while"_s; }
@@ -34,14 +35,15 @@ public:
   bool Replay(std::vector<cmListFileFunction> functions,
               cmExecutionStatus& inStatus) override;
 
-  std::vector<cmListFileArgument> Args;
-
 private:
   cmMakefile* Makefile;
+  std::vector<cmListFileArgument> Args;
 };
 
-cmWhileFunctionBlocker::cmWhileFunctionBlocker(cmMakefile* mf)
-  : Makefile(mf)
+cmWhileFunctionBlocker::cmWhileFunctionBlocker(
+  cmMakefile* const mf, std::vector<cmListFileArgument> args)
+  : Makefile{ mf }
+  , Args{ std::move(args) }
 {
   this->Makefile->PushLoopBlock();
 }
@@ -60,39 +62,29 @@ bool cmWhileFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
 bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
                                     cmExecutionStatus& inStatus)
 {
-  cmMakefile& mf = inStatus.GetMakefile();
-  std::string errorString;
-
-  std::vector<cmExpandedCommandArgument> expandedArguments;
-  mf.ExpandArguments(this->Args, expandedArguments);
-  MessageType messageType;
+  auto& mf = inStatus.GetMakefile();
 
   cmListFileBacktrace whileBT =
     mf.GetBacktrace().Push(this->GetStartingContext());
-  cmConditionEvaluator conditionEvaluator(mf, whileBT);
-
-  bool isTrue =
-    conditionEvaluator.IsTrue(expandedArguments, errorString, messageType);
-
-  while (isTrue) {
-    if (!errorString.empty()) {
-      std::string err = "had incorrect arguments: ";
-      for (cmListFileArgument const& arg : this->Args) {
-        err += (arg.Delim ? "\"" : "");
-        err += arg.Value;
-        err += (arg.Delim ? "\"" : "");
-        err += " ";
-      }
-      err += "(";
-      err += errorString;
-      err += ").";
-      mf.GetCMakeInstance()->IssueMessage(messageType, err, whileBT);
-      if (messageType == MessageType::FATAL_ERROR) {
-        cmSystemTools::SetFatalErrorOccured();
-        return true;
-      }
-    }
 
+  std::vector<cmExpandedCommandArgument> expandedArguments;
+  // At least same size expected for `expandedArguments` as `Args`
+  expandedArguments.reserve(this->Args.size());
+
+  auto expandArgs = [&mf](std::vector<cmListFileArgument> const& args,
+                          std::vector<cmExpandedCommandArgument>& out)
+    -> std::vector<cmExpandedCommandArgument>& {
+    out.clear();
+    mf.ExpandArguments(args, out);
+    return out;
+  };
+
+  std::string errorString;
+  MessageType messageType;
+
+  for (cmConditionEvaluator conditionEvaluator(mf, whileBT);
+       conditionEvaluator.IsTrue(expandArgs(this->Args, expandedArguments),
+                                 errorString, messageType);) {
     // Invoke all the functions that were collected in the block.
     for (cmListFileFunction const& fn : functions) {
       cmExecutionStatus status(mf);
@@ -111,11 +103,22 @@ bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
         return true;
       }
     }
-    expandedArguments.clear();
-    mf.ExpandArguments(this->Args, expandedArguments);
-    isTrue =
-      conditionEvaluator.IsTrue(expandedArguments, errorString, messageType);
   }
+
+  if (!errorString.empty()) {
+    std::string err = "had incorrect arguments:\n ";
+    for (auto const& i : expandedArguments) {
+      err += " ";
+      err += cmOutputConverter::EscapeForCMake(i.GetValue());
+    }
+    err += "\n";
+    err += errorString;
+    mf.GetCMakeInstance()->IssueMessage(messageType, err, whileBT);
+    if (messageType == MessageType::FATAL_ERROR) {
+      cmSystemTools::SetFatalErrorOccured();
+    }
+  }
+
   return true;
 }
 
@@ -128,11 +131,9 @@ bool cmWhileCommand(std::vector<cmListFileArgument> const& args,
   }
 
   // create a function blocker
-  {
-    cmMakefile& makefile = status.GetMakefile();
-    auto fb = cm::make_unique<cmWhileFunctionBlocker>(&makefile);
-    fb->Args = args;
-    makefile.AddFunctionBlocker(std::move(fb));
-  }
+  auto& makefile = status.GetMakefile();
+  makefile.AddFunctionBlocker(
+    cm::make_unique<cmWhileFunctionBlocker>(&makefile, args));
+
   return true;
 }
index ff25526..4035650 100644 (file)
@@ -87,7 +87,7 @@ public:
      * Get the user data.
      * Only valid during the JobT::Process() call!
      */
-    void* UserData() const { return this->Pool_->UserData(); };
+    void* UserData() const { return this->Pool_->UserData(); }
 
     /**
      * Get the worker index.
@@ -138,7 +138,7 @@ public:
     {
     }
     //! Does nothing
-    void Process() override{};
+    void Process() override {}
   };
 
   /**
index e4329af..e2c0f2d 100644 (file)
@@ -204,7 +204,7 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout,
 
   // Info tab begin
 
-  if (cmProp exe =
+  if (cmValue exe =
         this->Target->GetTarget()->GetProperty("XCODE_SCHEME_EXECUTABLE")) {
 
     xout.StartElement("PathRunnable");
@@ -220,7 +220,7 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout,
 
   // Arguments tab begin
 
-  if (cmProp argList =
+  if (cmValue argList =
         this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ARGUMENTS")) {
     std::vector<std::string> arguments = cmExpandedList(*argList);
     if (!arguments.empty()) {
@@ -240,7 +240,7 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout,
     }
   }
 
-  if (cmProp envList =
+  if (cmValue envList =
         this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ENVIRONMENT")) {
     std::vector<std::string> envs = cmExpandedList(*envList);
     if (!envs.empty()) {
@@ -323,7 +323,7 @@ bool cmXCodeScheme::WriteLaunchActionBooleanAttribute(
   cmXMLWriter& xout, const std::string& attrName, const std::string& varName,
   bool defaultValue)
 {
-  cmProp property = Target->GetTarget()->GetProperty(varName);
+  cmValue property = Target->GetTarget()->GetProperty(varName);
   bool isOn = (!property && defaultValue) || cmIsOn(property);
 
   if (isOn) {
index 73f5ad5..fda7900 100644 (file)
 #  include "cmExtraSublimeTextGenerator.h"
 #endif
 
-#if defined(__linux__) || defined(_WIN32)
+// NOTE: the __linux__ macro is predefined on Android host too, but
+// main CMakeLists.txt filters out this generator by host name.
+#if (defined(__linux__) && !defined(__ANDROID__)) || defined(_WIN32)
 #  include "cmGlobalGhsMultiGenerator.h"
 #endif
 
@@ -156,17 +158,16 @@ static void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/,
 }
 #endif
 
-cmake::cmake(Role role, cmState::Mode mode)
+cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind)
   : CMakeWorkingDirectory(cmSystemTools::GetCurrentWorkingDirectory())
   , FileTimeCache(cm::make_unique<cmFileTimeCache>())
 #ifndef CMAKE_BOOTSTRAP
   , VariableWatch(cm::make_unique<cmVariableWatch>())
 #endif
-  , State(cm::make_unique<cmState>())
+  , State(cm::make_unique<cmState>(mode, projectKind))
   , Messenger(cm::make_unique<cmMessenger>())
 {
   this->TraceFile.close();
-  this->State->SetMode(mode);
   this->CurrentSnapshot = this->State->CreateBaseSnapshot();
 
 #ifdef __APPLE__
@@ -598,15 +599,14 @@ void cmake::ProcessCacheArg(const std::string& var, const std::string& value,
   bool haveValue = false;
   std::string cachedValue;
   if (this->WarnUnusedCli) {
-    if (cmProp v = this->State->GetInitializedCacheValue(var)) {
+    if (cmValue v = this->State->GetInitializedCacheValue(var)) {
       haveValue = true;
       cachedValue = *v;
     }
   }
 
-  this->AddCacheEntry(var, value.c_str(),
-                      "No help, variable specified on the command line.",
-                      type);
+  this->AddCacheEntry(
+    var, value, "No help, variable specified on the command line.", type);
 
   if (this->WarnUnusedCli) {
     if (!haveValue ||
@@ -1468,7 +1468,7 @@ void cmake::SetDirectoriesFromFile(const std::string& arg)
   // If there is a CMakeCache.txt file, use its settings.
   if (!cachePath.empty()) {
     if (this->LoadCache(cachePath)) {
-      cmProp existingValue =
+      cmValue existingValue =
         this->State->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
       if (existingValue) {
         this->SetHomeOutputDirectory(cachePath);
@@ -1516,16 +1516,15 @@ void cmake::SetDirectoriesFromFile(const std::string& arg)
 int cmake::AddCMakePaths()
 {
   // Save the value in the cache
-  this->AddCacheEntry("CMAKE_COMMAND",
-                      cmSystemTools::GetCMakeCommand().c_str(),
+  this->AddCacheEntry("CMAKE_COMMAND", cmSystemTools::GetCMakeCommand(),
                       "Path to CMake executable.", cmStateEnums::INTERNAL);
 #ifndef CMAKE_BOOTSTRAP
-  this->AddCacheEntry(
-    "CMAKE_CTEST_COMMAND", cmSystemTools::GetCTestCommand().c_str(),
-    "Path to ctest program executable.", cmStateEnums::INTERNAL);
-  this->AddCacheEntry(
-    "CMAKE_CPACK_COMMAND", cmSystemTools::GetCPackCommand().c_str(),
-    "Path to cpack program executable.", cmStateEnums::INTERNAL);
+  this->AddCacheEntry("CMAKE_CTEST_COMMAND", cmSystemTools::GetCTestCommand(),
+                      "Path to ctest program executable.",
+                      cmStateEnums::INTERNAL);
+  this->AddCacheEntry("CMAKE_CPACK_COMMAND", cmSystemTools::GetCPackCommand(),
+                      "Path to cpack program executable.",
+                      cmStateEnums::INTERNAL);
 #endif
   if (!cmSystemTools::FileExists(
         (cmSystemTools::GetCMakeRoot() + "/Modules/CMake.cmake"))) {
@@ -1537,7 +1536,7 @@ int cmake::AddCMakePaths()
       cmSystemTools::GetCMakeRoot());
     return 0;
   }
-  this->AddCacheEntry("CMAKE_ROOT", cmSystemTools::GetCMakeRoot().c_str(),
+  this->AddCacheEntry("CMAKE_ROOT", cmSystemTools::GetCMakeRoot(),
                       "Path to CMake installation.", cmStateEnums::INTERNAL);
 
   return 1;
@@ -1843,7 +1842,7 @@ int cmake::HandleDeleteCacheVariables(const std::string& var)
   std::vector<std::string> argsSplit = cmExpandedList(var, true);
   // erase the property to avoid infinite recursion
   this->State->SetGlobalProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_", "");
-  if (this->State->GetIsInTryCompile()) {
+  if (this->GetIsInTryCompile()) {
     return 0;
   }
   std::vector<SaveCacheEntry> saved;
@@ -1866,10 +1865,10 @@ int cmake::HandleDeleteCacheVariables(const std::string& var)
       warning << "\n";
       i -= 1;
     }
-    cmProp existingValue = this->State->GetCacheEntryValue(save.key);
+    cmValue existingValue = this->State->GetCacheEntryValue(save.key);
     if (existingValue) {
       save.type = this->State->GetCacheEntryType(save.key);
-      if (cmProp help =
+      if (cmValue help =
             this->State->GetCacheEntryProperty(save.key, "HELPSTRING")) {
         save.help = *help;
       }
@@ -1885,7 +1884,7 @@ int cmake::HandleDeleteCacheVariables(const std::string& var)
   this->LoadCache();
   // restore the changed compilers
   for (SaveCacheEntry const& i : saved) {
-    this->AddCacheEntry(i.key, i.value.c_str(), i.help.c_str(), i.type);
+    this->AddCacheEntry(i.key, i.value, i.help.c_str(), i.type);
   }
   cmSystemTools::Message(warning.str());
   // avoid reconfigure if there were errors
@@ -1918,9 +1917,9 @@ int cmake::Configure()
   if (this->DiagLevels.count("dev") == 1) {
     bool setDeprecatedVariables = false;
 
-    cmProp cachedWarnDeprecated =
+    cmValue cachedWarnDeprecated =
       this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED");
-    cmProp cachedErrorDeprecated =
+    cmValue cachedErrorDeprecated =
       this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED");
 
     // don't overwrite deprecated warning setting from a previous invocation
@@ -1959,7 +1958,7 @@ int cmake::Configure()
   // Cache variables may have already been set by a previous invocation,
   // so we cannot rely on command line options alone. Always ensure our
   // messenger is in sync with the cache.
-  cmProp value = this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED");
+  cmValue value = this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED");
   this->Messenger->SetSuppressDeprecatedWarnings(value && cmIsOff(*value));
 
   value = this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED");
@@ -1972,7 +1971,7 @@ int cmake::Configure()
   this->Messenger->SetDevWarningsAsErrors(value && cmIsOff(*value));
 
   int ret = this->ActualConfigure();
-  cmProp delCacheVars =
+  cmValue delCacheVars =
     this->State->GetGlobalProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_");
   if (delCacheVars && !delCacheVars->empty()) {
     return this->HandleDeleteCacheVariables(*delCacheVars);
@@ -1992,7 +1991,7 @@ int cmake::ActualConfigure()
   }
   if (!res) {
     this->AddCacheEntry(
-      "CMAKE_HOME_DIRECTORY", this->GetHomeDirectory().c_str(),
+      "CMAKE_HOME_DIRECTORY", this->GetHomeDirectory(),
       "Source directory with the top level CMakeLists.txt file for this "
       "project",
       cmStateEnums::INTERNAL);
@@ -2000,8 +1999,8 @@ int cmake::ActualConfigure()
 
   // no generator specified on the command line
   if (!this->GlobalGenerator) {
-    cmProp genName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR");
-    cmProp extraGenName =
+    cmValue genName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR");
+    cmValue extraGenName =
       this->State->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
     if (genName) {
       std::string fullName =
@@ -2024,7 +2023,7 @@ int cmake::ActualConfigure()
     }
   }
 
-  cmProp genName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR");
+  cmValue genName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR");
   if (genName) {
     if (!this->GlobalGenerator->MatchesGeneratorName(*genName)) {
       std::string message =
@@ -2037,26 +2036,24 @@ int cmake::ActualConfigure()
     }
   }
   if (!this->State->GetInitializedCacheValue("CMAKE_GENERATOR")) {
-    this->AddCacheEntry("CMAKE_GENERATOR",
-                        this->GlobalGenerator->GetName().c_str(),
+    this->AddCacheEntry("CMAKE_GENERATOR", this->GlobalGenerator->GetName(),
                         "Name of generator.", cmStateEnums::INTERNAL);
-    this->AddCacheEntry("CMAKE_EXTRA_GENERATOR",
-                        this->GlobalGenerator->GetExtraGeneratorName().c_str(),
-                        "Name of external makefile project generator.",
-                        cmStateEnums::INTERNAL);
+    this->AddCacheEntry(
+      "CMAKE_EXTRA_GENERATOR", this->GlobalGenerator->GetExtraGeneratorName(),
+      "Name of external makefile project generator.", cmStateEnums::INTERNAL);
 
     if (!this->State->GetInitializedCacheValue("CMAKE_TOOLCHAIN_FILE")) {
       std::string envToolchain;
       if (cmSystemTools::GetEnv("CMAKE_TOOLCHAIN_FILE", envToolchain) &&
           !envToolchain.empty()) {
-        this->AddCacheEntry("CMAKE_TOOLCHAIN_FILE", envToolchain.c_str(),
+        this->AddCacheEntry("CMAKE_TOOLCHAIN_FILE", envToolchain,
                             "The CMake toolchain file",
                             cmStateEnums::FILEPATH);
       }
     }
   }
 
-  if (cmProp instance =
+  if (cmValue instance =
         this->State->GetInitializedCacheValue("CMAKE_GENERATOR_INSTANCE")) {
     if (this->GeneratorInstanceSet && this->GeneratorInstance != *instance) {
       std::string message =
@@ -2068,12 +2065,12 @@ int cmake::ActualConfigure()
       return -2;
     }
   } else {
-    this->AddCacheEntry(
-      "CMAKE_GENERATOR_INSTANCE", this->GeneratorInstance.c_str(),
-      "Generator instance identifier.", cmStateEnums::INTERNAL);
+    this->AddCacheEntry("CMAKE_GENERATOR_INSTANCE", this->GeneratorInstance,
+                        "Generator instance identifier.",
+                        cmStateEnums::INTERNAL);
   }
 
-  if (cmProp platformName =
+  if (cmValue platformName =
         this->State->GetInitializedCacheValue("CMAKE_GENERATOR_PLATFORM")) {
     if (this->GeneratorPlatformSet &&
         this->GeneratorPlatform != *platformName) {
@@ -2086,12 +2083,11 @@ int cmake::ActualConfigure()
       return -2;
     }
   } else {
-    this->AddCacheEntry("CMAKE_GENERATOR_PLATFORM",
-                        this->GeneratorPlatform.c_str(),
+    this->AddCacheEntry("CMAKE_GENERATOR_PLATFORM", this->GeneratorPlatform,
                         "Name of generator platform.", cmStateEnums::INTERNAL);
   }
 
-  if (cmProp tsName =
+  if (cmValue tsName =
         this->State->GetInitializedCacheValue("CMAKE_GENERATOR_TOOLSET")) {
     if (this->GeneratorToolsetSet && this->GeneratorToolset != *tsName) {
       std::string message =
@@ -2103,15 +2099,14 @@ int cmake::ActualConfigure()
       return -2;
     }
   } else {
-    this->AddCacheEntry("CMAKE_GENERATOR_TOOLSET",
-                        this->GeneratorToolset.c_str(),
+    this->AddCacheEntry("CMAKE_GENERATOR_TOOLSET", this->GeneratorToolset,
                         "Name of generator toolset.", cmStateEnums::INTERNAL);
   }
 
   // reset any system configuration information, except for when we are
   // InTryCompile. With TryCompile the system info is taken from the parent's
   // info to save time
-  if (!this->State->GetIsInTryCompile()) {
+  if (!this->GetIsInTryCompile()) {
     this->GlobalGenerator->ClearEnabledLanguages();
 
     this->TruncateOutputLog("CMakeOutput.log");
@@ -2415,7 +2410,7 @@ int cmake::Generate()
   return 0;
 }
 
-void cmake::AddCacheEntry(const std::string& key, const char* value,
+void cmake::AddCacheEntry(const std::string& key, cmValue value,
                           const char* helpString, int type)
 {
   this->State->AddCacheEntry(key, value, helpString,
@@ -2491,7 +2486,7 @@ std::string cmake::StripExtension(const std::string& file) const
   return file;
 }
 
-cmProp cmake::GetCacheDefinition(const std::string& name) const
+cmValue cmake::GetCacheDefinition(const std::string& name) const
 {
   return this->State->GetInitializedCacheValue(name);
 }
@@ -2529,7 +2524,7 @@ void cmake::AddDefaultGenerators()
   this->Generators.push_back(cmGlobalMinGWMakefileGenerator::NewFactory());
 #endif
 #if !defined(CMAKE_BOOTSTRAP)
-#  if defined(__linux__) || defined(_WIN32)
+#  if (defined(__linux__) && !defined(__ANDROID__)) || defined(_WIN32)
   this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory());
 #  endif
   this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory());
@@ -2622,19 +2617,14 @@ void cmake::SetProgressCallback(ProgressCallbackType f)
 
 void cmake::UpdateProgress(const std::string& msg, float prog)
 {
-  if (this->ProgressCallback && !this->State->GetIsInTryCompile()) {
+  if (this->ProgressCallback && !this->GetIsInTryCompile()) {
     this->ProgressCallback(msg, prog);
   }
 }
 
 bool cmake::GetIsInTryCompile() const
 {
-  return this->State->GetIsInTryCompile();
-}
-
-void cmake::SetIsInTryCompile(bool b)
-{
-  this->State->SetIsInTryCompile(b);
+  return this->State->GetProjectKind() == cmState::ProjectKind::TryCompile;
 }
 
 void cmake::AppendGlobalGeneratorsDocumentation(
@@ -2705,7 +2695,7 @@ void cmake::PrintGeneratorList()
 void cmake::UpdateConversionPathTable()
 {
   // Update the path conversion table with any specified file:
-  cmProp tablepath =
+  cmValue tablepath =
     this->State->GetInitializedCacheValue("CMAKE_PATH_TRANSLATION_FILE");
 
   if (tablepath) {
@@ -2923,6 +2913,10 @@ void cmake::SetProperty(const std::string& prop, const char* value)
 {
   this->State->SetGlobalProperty(prop, value);
 }
+void cmake::SetProperty(const std::string& prop, cmValue value)
+{
+  this->State->SetGlobalProperty(prop, value);
+}
 
 void cmake::AppendProperty(const std::string& prop, const std::string& value,
                            bool asString)
@@ -2930,7 +2924,7 @@ void cmake::AppendProperty(const std::string& prop, const std::string& value,
   this->State->AppendGlobalProperty(prop, value, asString);
 }
 
-cmProp cmake::GetProperty(const std::string& prop)
+cmValue cmake::GetProperty(const std::string& prop)
 {
   return this->State->GetGlobalProperty(prop);
 }
@@ -3175,7 +3169,7 @@ void cmake::IssueMessage(MessageType t, std::string const& text,
 std::vector<std::string> cmake::GetDebugConfigs()
 {
   std::vector<std::string> configs;
-  if (cmProp config_list =
+  if (cmValue config_list =
         this->State->GetGlobalProperty("DEBUG_CONFIGURATIONS")) {
     // Expand the specified list and convert to upper-case.
     cmExpandList(*config_list, configs);
@@ -3324,7 +3318,7 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
     std::cerr << "Error: could not load cache\n";
     return 1;
   }
-  cmProp cachedGenerator = this->State->GetCacheEntryValue("CMAKE_GENERATOR");
+  cmValue cachedGenerator = this->State->GetCacheEntryValue("CMAKE_GENERATOR");
   if (!cachedGenerator) {
     std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n";
     return 1;
@@ -3336,7 +3330,7 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
     return 1;
   }
   this->SetGlobalGenerator(std::move(gen));
-  cmProp cachedGeneratorInstance =
+  cmValue cachedGeneratorInstance =
     this->State->GetCacheEntryValue("CMAKE_GENERATOR_INSTANCE");
   if (cachedGeneratorInstance) {
     cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot());
@@ -3345,7 +3339,7 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
       return 1;
     }
   }
-  cmProp cachedGeneratorPlatform =
+  cmValue cachedGeneratorPlatform =
     this->State->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM");
   if (cachedGeneratorPlatform) {
     cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot());
@@ -3354,7 +3348,7 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
       return 1;
     }
   }
-  cmProp cachedGeneratorToolset =
+  cmValue cachedGeneratorToolset =
     this->State->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET");
   if (cachedGeneratorToolset) {
     cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot());
@@ -3365,7 +3359,7 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
   }
   std::string output;
   std::string projName;
-  cmProp cachedProjectName =
+  cmValue cachedProjectName =
     this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME");
   if (!cachedProjectName) {
     std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n";
@@ -3457,12 +3451,12 @@ bool cmake::Open(const std::string& dir, bool dryRun)
     std::cerr << "Error: could not load cache\n";
     return false;
   }
-  cmProp genName = this->State->GetCacheEntryValue("CMAKE_GENERATOR");
+  cmValue genName = this->State->GetCacheEntryValue("CMAKE_GENERATOR");
   if (!genName) {
     std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n";
     return false;
   }
-  cmProp extraGenName =
+  cmValue extraGenName =
     this->State->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
   std::string fullName =
     cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
@@ -3476,7 +3470,7 @@ bool cmake::Open(const std::string& dir, bool dryRun)
     return false;
   }
 
-  cmProp cachedProjectName =
+  cmValue cachedProjectName =
     this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME");
   if (!cachedProjectName) {
     std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n";
@@ -3540,7 +3534,7 @@ void cmake::SetSuppressDevWarnings(bool b)
     value = "FALSE";
   }
 
-  this->AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", value.c_str(),
+  this->AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", value,
                       "Suppress Warnings that are meant for"
                       " the author of the CMakeLists.txt files.",
                       cmStateEnums::INTERNAL);
@@ -3564,7 +3558,7 @@ void cmake::SetSuppressDeprecatedWarnings(bool b)
     value = "TRUE";
   }
 
-  this->AddCacheEntry("CMAKE_WARN_DEPRECATED", value.c_str(),
+  this->AddCacheEntry("CMAKE_WARN_DEPRECATED", value,
                       "Whether to issue warnings for deprecated "
                       "functionality.",
                       cmStateEnums::INTERNAL);
@@ -3588,7 +3582,7 @@ void cmake::SetDevWarningsAsErrors(bool b)
     value = "TRUE";
   }
 
-  this->AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_ERRORS", value.c_str(),
+  this->AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_ERRORS", value,
                       "Suppress errors that are meant for"
                       " the author of the CMakeLists.txt files.",
                       cmStateEnums::INTERNAL);
@@ -3612,7 +3606,7 @@ void cmake::SetDeprecatedWarningsAsErrors(bool b)
     value = "FALSE";
   }
 
-  this->AddCacheEntry("CMAKE_ERROR_DEPRECATED", value.c_str(),
+  this->AddCacheEntry("CMAKE_ERROR_DEPRECATED", value,
                       "Whether to issue deprecation errors for macros"
                       " and functions.",
                       cmStateEnums::INTERNAL);
index 5a2a88f..3f2b2ed 100644 (file)
 #include "cmInstalledFile.h"
 #include "cmListFileCache.h"
 #include "cmMessageType.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
+#include "cmValue.h"
 
 #if !defined(CMAKE_BOOTSTRAP)
 #  include <cm/optional>
@@ -168,7 +168,8 @@ public:
   static const int DEFAULT_BUILD_PARALLEL_LEVEL = 0;
 
   /// Default constructor
-  cmake(Role role, cmState::Mode mode);
+  cmake(Role role, cmState::Mode mode,
+        cmState::ProjectKind projectKind = cmState::ProjectKind::Normal);
   /// Destructor
   ~cmake();
 
@@ -328,9 +329,21 @@ public:
   /**
    * Given a variable name, return its value (as a string).
    */
-  cmProp GetCacheDefinition(const std::string&) const;
+  cmValue GetCacheDefinition(const std::string&) const;
   //! Add an entry into the cache
   void AddCacheEntry(const std::string& key, const char* value,
+                     const char* helpString, int type)
+  {
+    this->AddCacheEntry(key,
+                        value ? cmValue(std::string(value)) : cmValue(nullptr),
+                        helpString, type);
+  }
+  void AddCacheEntry(const std::string& key, const std::string& value,
+                     const char* helpString, int type)
+  {
+    this->AddCacheEntry(key, cmValue(value), helpString, type);
+  }
+  void AddCacheEntry(const std::string& key, cmValue value,
                      const char* helpString, int type);
 
   bool DoWriteGlobVerifyTarget() const;
@@ -356,7 +369,6 @@ public:
 
   //! Is this cmake running as a result of a TRY_COMPILE command
   bool GetIsInTryCompile() const;
-  void SetIsInTryCompile(bool b);
 
 #ifndef CMAKE_BOOTSTRAP
   void SetWarningFromPreset(const std::string& name,
@@ -396,9 +408,14 @@ public:
 
   //! Set/Get a property of this target file
   void SetProperty(const std::string& prop, const char* value);
+  void SetProperty(const std::string& prop, cmValue value);
+  void SetProperty(const std::string& prop, const std::string& value)
+  {
+    this->SetProperty(prop, cmValue(value));
+  }
   void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString = false);
-  cmProp GetProperty(const std::string& prop);
+  cmValue GetProperty(const std::string& prop);
   bool GetPropertyAsBool(const std::string& prop);
 
   //! Get or create an cmInstalledFile instance and return a pointer to it
index 95ad320..61d4ae4 100644 (file)
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageMetadata.h"
-#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmValue.h"
 #include "cmake.h"
 #include "cmcmd.h"
 
@@ -161,11 +161,11 @@ void cmakemainMessageCallback(const std::string& m,
   // cannot use it to print messages.  Another implementation will
   // be needed to print colored messages on Windows.
   static_cast<void>(md);
-  std::cerr << m << cmakemainGetStack(cm) << '\n' << std::flush;
+  std::cerr << m << cmakemainGetStack(cm) << "\n";
 #else
   cmsysTerminal_cfprintf(md.desiredColor, stderr, "%s", m.c_str());
   fflush(stderr); // stderr is buffered in some cases.
-  std::cerr << cmakemainGetStack(cm) << '\n' << std::flush;
+  std::cerr << cmakemainGetStack(cm) << "\n";
 #endif
 }
 
@@ -375,11 +375,11 @@ int do_cmake(int ac, char const* const* av)
       cmStateEnums::CacheEntryType t = cm.GetState()->GetCacheEntryType(k);
       if (t != cmStateEnums::INTERNAL && t != cmStateEnums::STATIC &&
           t != cmStateEnums::UNINITIALIZED) {
-        cmProp advancedProp =
+        cmValue advancedProp =
           cm.GetState()->GetCacheEntryProperty(k, "ADVANCED");
         if (list_all_cached || !advancedProp) {
           if (list_help) {
-            cmProp help =
+            cmValue help =
               cm.GetState()->GetCacheEntryProperty(k, "HELPSTRING");
             std::cout << "// " << (help ? *help : "") << std::endl;
           }
index db45add..bdddc4e 100644 (file)
@@ -23,6 +23,7 @@
 #include "cmTransformDepfile.h"
 #include "cmUVProcessChain.h"
 #include "cmUtils.hxx"
+#include "cmValue.h"
 #include "cmVersion.h"
 #include "cmake.h"
 
@@ -385,18 +386,15 @@ int HandleTidy(const std::string& runCmd, const std::string& sourceFile,
   return ret;
 }
 
-int HandleLWYU(const std::string& runCmd, const std::string& /* sourceFile */,
+int HandleLWYU(const std::string& runCmd, const std::string& sourceFile,
                const std::vector<std::string>&)
 {
   // Construct the ldd -r -u (link what you use lwyu) command line
   // ldd -u -r lwuy target
-  std::vector<std::string> lwyu_cmd;
-  lwyu_cmd.emplace_back("ldd");
-  lwyu_cmd.emplace_back("-u");
-  lwyu_cmd.emplace_back("-r");
-  lwyu_cmd.push_back(runCmd);
+  std::vector<std::string> lwyu_cmd = cmExpandedList(runCmd, true);
+  lwyu_cmd.push_back(sourceFile);
 
-  // Run the ldd -u -r command line.
+  // Run the lwyu check command line,  currently ldd is expected.
   // Capture its stdout and hide its stderr.
   // Ignore its return code because the tool always returns non-zero
   // if there are any warnings, but we just want to warn.
@@ -1071,6 +1069,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
         } else if (!cmSystemTools::FileExists(arg)) {
           cmSystemTools::Error(arg + ": no such file or directory (ignoring)");
           return_value = 1;
+        } else if (cmSystemTools::FileLength(arg) == 0) {
+          // Ignore empty files, this is not an error
         } else {
           // Destroy console buffers to drop cout/cerr encoding transform.
           consoleBuf.reset();
index ed46d5c..16efaef 100644 (file)
@@ -55,7 +55,10 @@ public:
 #endif
 
   /** Return true on "Success", false otherwise.  */
-  explicit operator bool() const { return this->Kind_ == Kind::Success; }
+  bool IsSuccess() const { return this->Kind_ == Kind::Success; }
+
+  /** Return true on "Success", false otherwise.  */
+  explicit operator bool() const { return this->IsSuccess(); }
 
   /** Return the kind of status.  */
   Kind GetKind() const { return this->Kind_; }
index 12f9139..f2bf85f 100644 (file)
@@ -1356,14 +1356,12 @@ std::string SymbolProperties::Demangle(const char* symbol) const
   std::string result = safes(symbol);
 #  if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
   int status = 0;
-  size_t bufferLen = 1024;
-  char* buffer = (char*)malloc(1024);
   char* demangledSymbol =
-    abi::__cxa_demangle(symbol, buffer, &bufferLen, &status);
+    abi::__cxa_demangle(symbol, nullptr, nullptr, &status);
   if (!status) {
     result = demangledSymbol;
   }
-  free(buffer);
+  free(demangledSymbol);
 #  else
   (void)symbol;
 #  endif
index f610a70..930d84c 100644 (file)
@@ -2423,7 +2423,7 @@ Status SystemTools::CopyFileAlways(std::string const& source,
 
   if (SystemTools::FileIsDirectory(source)) {
     status = SystemTools::MakeDirectory(destination);
-    if (!status) {
+    if (!status.IsSuccess()) {
       return status;
     }
   } else {
@@ -2448,17 +2448,17 @@ Status SystemTools::CopyFileAlways(std::string const& source,
     // Create destination directory
     if (!destination_dir.empty()) {
       status = SystemTools::MakeDirectory(destination_dir);
-      if (!status) {
+      if (!status.IsSuccess()) {
         return status;
       }
     }
 
     status = SystemTools::CloneFileContent(source, real_destination);
     // if cloning did not succeed, fall back to blockwise copy
-    if (!status) {
+    if (!status.IsSuccess()) {
       status = SystemTools::CopyFileContentBlockwise(source, real_destination);
     }
-    if (!status) {
+    if (!status.IsSuccess()) {
       return status;
     }
   }
@@ -2488,11 +2488,11 @@ Status SystemTools::CopyADirectory(std::string const& source,
   Status status;
   Directory dir;
   status = dir.Load(source);
-  if (!status) {
+  if (!status.IsSuccess()) {
     return status;
   }
   status = SystemTools::MakeDirectory(destination);
-  if (!status) {
+  if (!status.IsSuccess()) {
     return status;
   }
 
@@ -2507,12 +2507,12 @@ Status SystemTools::CopyADirectory(std::string const& source,
         fullDestPath += "/";
         fullDestPath += dir.GetFile(static_cast<unsigned long>(fileNum));
         status = SystemTools::CopyADirectory(fullPath, fullDestPath, always);
-        if (!status) {
+        if (!status.IsSuccess()) {
           return status;
         }
       } else {
         status = SystemTools::CopyAFile(fullPath, destination, always);
-        if (!status) {
+        if (!status.IsSuccess()) {
           return status;
         }
       }
@@ -2664,7 +2664,7 @@ Status SystemTools::RemoveADirectory(std::string const& source)
   Status status;
   Directory dir;
   status = dir.Load(source);
-  if (!status) {
+  if (!status.IsSuccess()) {
     return status;
   }
 
@@ -2678,12 +2678,12 @@ Status SystemTools::RemoveADirectory(std::string const& source)
       if (SystemTools::FileIsDirectory(fullPath) &&
           !SystemTools::FileIsSymlink(fullPath)) {
         status = SystemTools::RemoveADirectory(fullPath);
-        if (!status) {
+        if (!status.IsSuccess()) {
           return status;
         }
       } else {
         status = SystemTools::RemoveFile(fullPath);
-        if (!status) {
+        if (!status.IsSuccess()) {
           return status;
         }
       }
@@ -3147,7 +3147,7 @@ Status SystemTools::ReadSymlink(std::string const& newName,
     status = Status::Windows_GetLastError();
   }
   CloseHandle(hFile);
-  if (!status) {
+  if (!status.IsSuccess()) {
     return status;
   }
   PREPARSE_DATA_BUFFER data =
index 06a22dc..a847462 100644 (file)
@@ -122,7 +122,7 @@ int _copyDirectoryTest()
   }
   const Status copysuccess = SystemTools::CopyADirectory(source, destination);
   const bool destinationexists = SystemTools::PathExists(destination);
-  if (copysuccess) {
+  if (copysuccess.IsSuccess()) {
     std::cerr << "CopyADirectory should have returned false" << std::endl;
     SystemTools::RemoveADirectory(destination);
     return 3;
index f85ef42..0a767a8 100644 (file)
@@ -31,6 +31,10 @@ int testStatus(int, char* [])
       std::cerr << "Status Success constructor does not produce Success\n";
       res = false;
     }
+    if (!status.IsSuccess()) {
+      std::cerr << "Status Success gives false IsSuccess\n";
+      res = false;
+    }
     if (!status) {
       std::cerr << "Status Success kind is not true\n";
       res = false;
@@ -55,6 +59,10 @@ int testStatus(int, char* [])
       std::cerr << "Status POSIX constructor does not produce POSIX\n";
       res = false;
     }
+    if (status.IsSuccess()) {
+      std::cerr << "Status POSIX gives true IsSuccess\n";
+      res = false;
+    }
     if (status) {
       std::cerr << "Status POSIX kind is not false\n";
       res = false;
@@ -87,6 +95,10 @@ int testStatus(int, char* [])
       std::cerr << "Status Windows constructor does not produce Windows\n";
       res = false;
     }
+    if (status.IsSuccess()) {
+      std::cerr << "Status Windows gives true IsSuccess\n";
+      res = false;
+    }
     if (status) {
       std::cerr << "Status Windows kind is not false\n";
       res = false;
index 39a19cb..6ccc7a7 100644 (file)
@@ -436,7 +436,7 @@ static bool CheckFileOperations()
   if (symlinkStatus.GetWindows() != ERROR_PRIVILEGE_NOT_HELD)
 #endif
   {
-    if (!symlinkStatus) {
+    if (!symlinkStatus.IsSuccess()) {
       std::cerr << "CreateSymlink for: " << testBadSymlink << " -> "
                 << testBadSymlinkTgt
                 << " failed: " << symlinkStatus.GetString() << std::endl;
index 4422f55..71d58f8 100644 (file)
     "flags": []
   },
   {
+    "name": "LinkControlFlowGuard",
+    "switch": "guard:cf",
+    "comment": "Control Flow Guard",
+    "value": "true",
+    "flags": []
+  },
+  {
     "name": "LinkGuardEHContMetadata",
     "switch": "guard:ehcont",
     "comment": "Enable EH Continuation Metadata",
index 4870f65..5e3cdb1 100644 (file)
@@ -116,6 +116,12 @@ A literal block can be empty::
 .. note::
  Notes are called out.
 
+.. versionadded:: 1.2
+ Version blocks are preserved.
+
+.. versionchanged:: 2.3
+ Version blocks are preserved.
+
 substituted text with multiple lines becomes one line
 
 End of first include.
index 44931a7..4139801 100644 (file)
@@ -123,6 +123,12 @@ A literal block can be empty::
 .. note::
  Notes are called out.
 
+.. versionadded:: 1.2
+ Version blocks are preserved.
+
+.. versionchanged:: 2.3
+ Version blocks are preserved.
+
 .. |substitution| replace::
    |nested substitution|
    with multiple lines becomes one line
index 0607f44..7d21959 100644 (file)
@@ -169,7 +169,7 @@ static bool testAllMoves()
   allTypes b(std::move(a));
   allTypes c = std::move(b);
   return true;
-};
+}
 
 static bool testLoopReset()
 {
@@ -192,7 +192,7 @@ static bool testLoopReset()
   }
 
   return true;
-};
+}
 
 static bool testLoopDestructor()
 {
@@ -217,7 +217,7 @@ static bool testLoopDestructor()
   }
 
   return true;
-};
+}
 
 int testUVRAII(int, char** const)
 {
index 341aba6..ecb54c7 100644 (file)
@@ -39,6 +39,13 @@ set(ENV{HOME} \"${TEST_HOME}\")
 ")
 endif()
 
+# Suppress generator deprecation warnings in test suite.
+if(CMAKE_GENERATOR MATCHES "^Visual Studio 10 2010")
+  set(TEST_WARN_VS10_CODE "set(ENV{CMAKE_WARN_VS10} OFF)")
+else()
+  set(TEST_WARN_VS10_CODE "")
+endif()
+
 # 3.9 or later provides a definitive answer to whether we are multi-config
 # through a global property. Prior to 3.9, CMAKE_CONFIGURATION_TYPES being set
 # is assumed to mean multi-config, but developers might modify it so it is
@@ -250,6 +257,13 @@ if(BUILD_TESTING)
   #---------------------------------------------------------------------------
   # Add tests below here.
 
+  if(NOT DEFINED CMake_TEST_Qt6)
+    set(CMake_TEST_Qt6 1)
+  endif()
+  if(CMake_TEST_Qt6)
+    find_package(Qt6 COMPONENTS Core Widgets QUIET NO_MODULE)
+  endif()
+
   if(NOT DEFINED CMake_TEST_Qt5)
     set(CMake_TEST_Qt5 1)
   endif()
@@ -1365,6 +1379,13 @@ if(BUILD_TESTING)
     --test-command ${CMAKE_CTEST_COMMAND} -V
     )
   list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Environment")
+  set_property(TEST Environment APPEND
+    PROPERTY ENVIRONMENT
+      "SET_FROM_AMBIENT_unset=base"
+      "SET_FROM_AMBIENT_replace=base"
+      "SET_FROM_AMBIENT_string=base"
+      "SET_FROM_AMBIENT_path=base"
+      "SET_FROM_AMBIENT_list=base")
 
   add_test(QtAutomocNoQt  ${CMAKE_CTEST_COMMAND}
     --build-and-test
@@ -1377,6 +1398,9 @@ if(BUILD_TESTING)
     )
   list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomocNoQt")
 
+  if(CMake_TEST_Qt6 AND Qt6Widgets_FOUND)
+    add_subdirectory(Qt6Autogen)
+  endif()
   if(CMake_TEST_Qt5 AND Qt5Widgets_FOUND)
     add_subdirectory(Qt5Autogen)
   endif()
@@ -1442,12 +1466,14 @@ if(BUILD_TESTING)
             GIF
             Git
             GLEW
+            GLUT
             GnuTLS
             GSL
             GTK2
             Iconv
             ICU
             Intl
+            Jasper
             JPEG
             JsonCpp
             LAPACK
@@ -1543,6 +1569,8 @@ if(BUILD_TESTING)
     ADD_TEST_MACRO(FindMatlab.failure_reports   ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>)
     set(FindMatlab.r2018a_check_BUILD_OPTIONS ${FindMatlab_additional_test_options})
     ADD_TEST_MACRO(FindMatlab.r2018a_check   ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>)
+    set(FindMatlab.targets_checks_BUILD_OPTIONS ${FindMatlab_additional_test_options})
+    ADD_TEST_MACRO(FindMatlab.targets_checks      ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>)
   endif()
 
   add_test(ExternalProject ${CMAKE_CTEST_COMMAND}
@@ -1640,6 +1668,55 @@ if(BUILD_TESTING)
     WORKING_DIRECTORY ${CMake_SOURCE_DIR}/Tests/ExternalProjectUpdate
     DEPENDS ExternalProjectUpdateSetup )
 
+  execute_process(
+    COMMAND ${CMAKE_COMMAND}
+    "-E" create_symlink
+    "${CMake_SOURCE_DIR}/Tests/CMakeLists.txt"        # random source file that exists
+    "${CMake_BINARY_DIR}/Tests/try_to_create_symlink" # random target file in existing directory
+    RESULT_VARIABLE _symlink_result
+    OUTPUT_VARIABLE _symlink_stdout
+    ERROR_VARIABLE _symlink_stderr
+    )
+  if(_symlink_result EQUAL 0)
+    file(REMOVE "${CMake_BINARY_DIR}/Tests/try_to_create_symlink")
+    function(add_installmode_test _mode)
+      set(ENV{CMAKE_INSTALL_MODE} _mode)
+      set(_maybe_InstallMode_CTEST_OPTIONS)
+      set(_maybe_BUILD_OPTIONS)
+      if(_isMultiConfig)
+        set(_maybe_CTEST_OPTIONS -C $<CONFIGURATION>)
+      else()
+        set(_maybe_BUILD_OPTIONS "-DCMAKE_BUILD_TYPE=$<CONFIGURATION>")
+      endif()
+      add_test(
+        NAME "InstallMode-${_mode}"
+        COMMAND
+          ${CMAKE_CTEST_COMMAND} -V ${_maybe_CTEST_OPTIONS}
+        --build-and-test
+          "${CMake_SOURCE_DIR}/Tests/InstallMode"
+          "${CMake_BINARY_DIR}/Tests/InstallMode-${_mode}"
+        ${build_generator_args}
+        --build-project superpro
+        --build-exe-dir "${CMake_BINARY_DIR}/Tests/InstallMode-${_mode}"
+        --force-new-ctest-process
+        --build-options
+          ${_maybe_BUILD_OPTIONS}
+          "-DCMAKE_INSTALL_PREFIX:PATH=${CMake_BINARY_DIR}/Tests/InstallMode-${_mode}/install"
+        )
+      list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/InstallMode-${_mode}")
+      unset(ENV{CMAKE_INSTALL_MODE})
+    endfunction()
+
+    add_installmode_test(COPY)
+    add_installmode_test(REL_SYMLINK)
+    add_installmode_test(REL_SYMLINK_OR_COPY)
+    add_installmode_test(ABS_SYMLINK)
+    add_installmode_test(ABS_SYMLINK_OR_COPY)
+    add_installmode_test(SYMLINK)
+    add_installmode_test(SYMLINK_OR_COPY)
+  endif()
+
+
   # do each of the tutorial steps
   function(add_tutorial_test step_name use_mymath tutorial_arg pass_regex)
     set(tutorial_test_name Tutorial${step_name})
index 52959e6..9e0b891 100644 (file)
@@ -31,7 +31,6 @@ AddCMakeTest(CompilerIdVendor "")
 AddCMakeTest(ProcessorCount "-DKWSYS_TEST_EXE=$<TARGET_FILE:cmsysTestsCxx>")
 AddCMakeTest(PushCheckState "")
 AddCMakeTest(While "")
-AddCMakeTest(CMakeHostSystemInformation "")
 
 AddCMakeTest(FileDownload "")
 set_tests_properties(CMake.FileDownload PROPERTIES
index 64a8ef6..5d6320b 100644 (file)
@@ -19,5 +19,6 @@ set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
 set(CPACK_NSIS_MANIFEST_DPI_AWARE ON)
 set(CPACK_NSIS_BRANDING_TEXT "CMake branding text")
 set(CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION "RIGHT")
+set(CPACK_NSIS_IGNORE_LICENSE_PAGE ON)
 
 include(CPack)
index 8bfcf26..31a2560 100644 (file)
@@ -60,3 +60,12 @@ if("${output_index}" EQUAL "-1")
 else()
   message(STATUS "Found BrandingText")
 endif()
+
+# license page should not be present
+file(STRINGS "${project_file}" line REGEX "!insertmacro MUI_PAGE_LICENSE")
+string(FIND "${line}" "MUI_PAGE_LICENSE" output_index)
+if("${output_index}" EQUAL "-1")
+  message(STATUS "License not found in the project")
+else()
+  message(FATAL_ERROR "License found in the project")
+endif()
index 28ee094..cf0d314 100644 (file)
@@ -2,6 +2,9 @@ set(CTEST_RUN_CURRENT_SCRIPT 0)
 
 set(LOCK_FILE "${TEST_NAME}.lock")
 
+# Delete the old lock file in case it's lingering from a previous failed test run
+file(REMOVE "${LOCK_FILE}")
+
 if("${TEST_NAME}" STREQUAL "i_want_to_be_alone")
        file(GLOB LOCK_FILES *.lock)
        if(LOCK_FILES)
index be5ccac..669c412 100644 (file)
@@ -4,7 +4,6 @@ macro (add_cuda_test_macro name)
     PROPERTY LABELS "CUDA")
 endmacro ()
 
-add_cuda_test_macro(Cuda.ConsumeCompileFeatures CudaConsumeCompileFeatures)
 add_cuda_test_macro(Cuda.CXXStandardSetTwice CXXStandardSetTwice)
 add_cuda_test_macro(Cuda.ObjectLibrary CudaObjectLibrary)
 add_cuda_test_macro(Cuda.MixedStandardLevels1 MixedStandardLevels1)
diff --git a/Tests/Cuda/ConsumeCompileFeatures/CMakeLists.txt b/Tests/Cuda/ConsumeCompileFeatures/CMakeLists.txt
deleted file mode 100644 (file)
index b01b9d7..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-cmake_minimum_required(VERSION 3.18)
-project(ConsumeCompileFeatures CXX CUDA)
-#Goal for this example:
-
-#build a c++11 library that express a c++11 public compile feature
-#link a cuda library and verify it builds with c++11 enabled
-
-#build a standalone c++/cuda mixed executable where we express a c++11
-#compile feature.
-
-
-add_library(CudaConsumeLib STATIC static.cpp static.cu)
-target_compile_features(CudaConsumeLib PUBLIC cxx_nullptr)
-
-add_executable(CudaConsumeCompileFeatures main.cu)
-target_link_libraries(CudaConsumeCompileFeatures PRIVATE CudaConsumeLib)
diff --git a/Tests/Cuda/ConsumeCompileFeatures/main.cu b/Tests/Cuda/ConsumeCompileFeatures/main.cu
deleted file mode 100644 (file)
index bc32450..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-
-#include <iostream>
-
-int static_cxx11_func(int);
-
-void test_functions()
-{
-  auto x = static_cxx11_func(int(42));
-  std::cout << x << std::endl;
-}
-
-int main(int argc, char** argv)
-{
-  test_functions();
-  std::cout
-    << "this executable doesn't use cuda code, just call methods defined"
-    << std::endl;
-  std::cout << "in libraries that have cuda code" << std::endl;
-  return 0;
-}
diff --git a/Tests/Cuda/ConsumeCompileFeatures/static.cpp b/Tests/Cuda/ConsumeCompileFeatures/static.cpp
deleted file mode 100644 (file)
index 565d52e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-#include <type_traits>
-
-int static_cuda11_func(int);
-
-int static_cxx11_func(int x)
-{
-  return static_cuda11_func(x) + std::integral_constant<int, 32>::value;
-}
diff --git a/Tests/Cuda/ConsumeCompileFeatures/static.cu b/Tests/Cuda/ConsumeCompileFeatures/static.cu
deleted file mode 100644 (file)
index 73e43a8..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-
-#include <type_traits>
-
-using tt = std::true_type;
-using ft = std::false_type;
-int __host__ static_cuda11_func(int x)
-{
-  return x * x + std::integral_constant<int, 17>::value;
-}
index 7781ded..7c6f76a 100644 (file)
@@ -36,3 +36,4 @@ unset(ENV{CMAKE_GENERATOR_TOOLSET})
 unset(ENV{CMAKE_EXPORT_COMPILE_COMMANDS})
 
 @TEST_HOME_ENV_CODE@
+@TEST_WARN_VS10_CODE@
index 2b18d24..abcf33c 100644 (file)
@@ -9,6 +9,7 @@ add_test(Environment1 Environment)
 add_test(Environment2 Environment)
 add_test(EchoEnvironment1 ${CMAKE_COMMAND} -E environment)
 add_test(EchoEnvironment2 ${CMAKE_COMMAND} -E environment)
+add_test(EchoEnvironment3 ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_SOURCE_DIR}/check_mod.cmake")
 
 # Make sure "CMAKE_ENV.*Happy Thanksgiving" is in the output of
 # the "1" tests:
@@ -24,3 +25,79 @@ set_tests_properties(Environment1 EchoEnvironment1 PROPERTIES
 set_tests_properties(Environment2 EchoEnvironment2 PROPERTIES
   FAIL_REGULAR_EXPRESSION "CMAKE_ENV.*Happy Thanksgiving"
 )
+
+set_property(TEST EchoEnvironment3
+  PROPERTY ENVIRONMENT
+    "SET_FROM_ENVIRONMENT_PROPERTY_unset=base"
+    "SET_FROM_ENVIRONMENT_PROPERTY_replace=base"
+    "SET_FROM_ENVIRONMENT_PROPERTY_string=base"
+    "SET_FROM_ENVIRONMENT_PROPERTY_path=base"
+    "SET_FROM_ENVIRONMENT_PROPERTY_list=base"
+)
+
+set_property(TEST EchoEnvironment3
+  PROPERTY ENVIRONMENT_MODIFICATION
+    # Modifying variables set in the ambient environment (see properties for
+    # this test in `Tests/CMakeLists.txt`).
+    "SET_FROM_AMBIENT_unset=unset:"
+    "SET_FROM_AMBIENT_replace=set:new"
+    "SET_FROM_AMBIENT_string=string_append:new"
+    "SET_FROM_AMBIENT_path=path_list_append:new"
+    "SET_FROM_AMBIENT_list=cmake_list_append:new"
+
+    # Modifying variables set in the `ENVIRONMENT` property.
+    "SET_FROM_ENVIRONMENT_PROPERTY_unset=unset:"
+    "SET_FROM_ENVIRONMENT_PROPERTY_replace=set:new"
+    "SET_FROM_ENVIRONMENT_PROPERTY_string=string_append:new"
+    "SET_FROM_ENVIRONMENT_PROPERTY_path=path_list_append:new"
+    "SET_FROM_ENVIRONMENT_PROPERTY_list=cmake_list_append:new"
+
+    # Variables expected to be unset.
+    "UNSET_EXPLICIT=set:value"
+    "UNSET_EXPLICIT=unset:"
+    "UNSET_VIA_RESET=set:value"
+    "UNSET_VIA_RESET=reset:"
+
+    # Direct settings.
+    "DIRECT=set:old"
+    "DIRECT=set:new"
+
+    # String manipulation.
+    "STRING_MANIP=set:-core-"
+    "STRING_MANIP=string_append:post-"
+    "STRING_MANIP=string_prepend:-pre"
+    "STRING_MANIP=string_append:suffix"
+    "STRING_MANIP=string_prepend:prefix"
+
+    # String manipulation on non-existent.
+    "STRING_DNE=string_append:post-"
+    "STRING_DNE=string_prepend:-pre"
+    "STRING_DNE=string_append:suffix"
+    "STRING_DNE=string_prepend:prefix"
+
+    # Path manipulation.
+    "PATH_MANIP=set:core"
+    "PATH_MANIP=path_list_append:post"
+    "PATH_MANIP=path_list_prepend:pre"
+    "PATH_MANIP=path_list_append:suffix"
+    "PATH_MANIP=path_list_prepend:prefix"
+
+    # Path manipulation on non-existent.
+    "PATH_DNE=path_list_append:post"
+    "PATH_DNE=path_list_prepend:pre"
+    "PATH_DNE=path_list_append:suffix"
+    "PATH_DNE=path_list_prepend:prefix"
+
+    # CMake list manipulation.
+    "CMAKE_LIST_MANIP=set:core"
+    "CMAKE_LIST_MANIP=cmake_list_append:post"
+    "CMAKE_LIST_MANIP=cmake_list_prepend:pre"
+    "CMAKE_LIST_MANIP=cmake_list_append:suffix"
+    "CMAKE_LIST_MANIP=cmake_list_prepend:prefix"
+
+    # CMake list manipulation on non-existent.
+    "CMAKE_LIST_DNE=cmake_list_append:post"
+    "CMAKE_LIST_DNE=cmake_list_prepend:pre"
+    "CMAKE_LIST_DNE=cmake_list_append:suffix"
+    "CMAKE_LIST_DNE=cmake_list_prepend:prefix"
+)
diff --git a/Tests/Environment/check_mod.cmake b/Tests/Environment/check_mod.cmake
new file mode 100644 (file)
index 0000000..0f885f0
--- /dev/null
@@ -0,0 +1,79 @@
+execute_process(
+  COMMAND ${CMAKE_COMMAND} -E environment
+  OUTPUT_VARIABLE out
+  ERROR_VARIABLE err
+  RESULT_VARIABLE res)
+
+if (res)
+  message(FATAL_ERROR "Failed with exit code ${res}: ${err}")
+endif ()
+
+if (CMAKE_HOST_WIN32)
+  set(path_sep ";")
+else ()
+  set(path_sep ":")
+endif ()
+
+set(unexpect_SET_FROM_AMBIENT_unset "")
+set(unexpect_SET_FROM_ENVIRONMENT_PROPERTY_unset "")
+set(unexpect_UNSET_EXPLICIT "")
+set(unexpect_UNSET_VIA_RESET "")
+set(expect_DIRECT "new")
+set(expect_STRING_MANIP "prefix-pre-core-post-suffix")
+set(expect_PATH_MANIP "prefix${path_sep}pre${path_sep}core${path_sep}post${path_sep}suffix")
+set(expect_CMAKE_LIST_MANIP "prefix;pre;core;post;suffix")
+set(expect_STRING_DNE "prefix-prepost-suffix")
+set(expect_PATH_DNE "prefix${path_sep}pre${path_sep}post${path_sep}suffix")
+set(expect_CMAKE_LIST_DNE "prefix;pre;post;suffix")
+set(expect_SET_FROM_AMBIENT_replace "new")
+set(expect_SET_FROM_AMBIENT_string "basenew")
+set(expect_SET_FROM_AMBIENT_path "base${path_sep}new")
+set(expect_SET_FROM_AMBIENT_list "base;new")
+set(expect_SET_FROM_ENVIRONMENT_PROPERTY_replace "new")
+set(expect_SET_FROM_ENVIRONMENT_PROPERTY_string "basenew")
+set(expect_SET_FROM_ENVIRONMENT_PROPERTY_path "base${path_sep}new")
+set(expect_SET_FROM_ENVIRONMENT_PROPERTY_list "base;new")
+
+set(expected_vars
+  SET_FROM_AMBIENT_replace
+  SET_FROM_AMBIENT_string
+  SET_FROM_AMBIENT_path
+  SET_FROM_AMBIENT_list
+  SET_FROM_ENVIRONMENT_PROPERTY_replace
+  SET_FROM_ENVIRONMENT_PROPERTY_string
+  SET_FROM_ENVIRONMENT_PROPERTY_path
+  SET_FROM_ENVIRONMENT_PROPERTY_list
+  DIRECT
+  STRING_MANIP
+  PATH_MANIP
+  CMAKE_LIST_MANIP
+  STRING_DNE
+  PATH_DNE
+  CMAKE_LIST_DNE)
+
+while (out)
+  string(FIND "${out}" "\n" nl_pos)
+  string(SUBSTRING "${out}" 0 "${nl_pos}" line)
+  math(EXPR line_next "${nl_pos} + 1")
+  string(SUBSTRING "${out}" "${line_next}" -1 out)
+
+  string(FIND "${line}" "=" eq_pos)
+  string(SUBSTRING "${line}" 0 "${eq_pos}" name)
+  math(EXPR value_start "${eq_pos} + 1")
+  string(SUBSTRING "${line}" "${value_start}" -1 value)
+
+  if (DEFINED "unexpect_${name}")
+    message(SEND_ERROR "Found `${name}=${value}` when it should have been unset")
+  elseif (DEFINED "expect_${name}")
+    list(REMOVE_ITEM expected_vars "${name}")
+    if (expect_${name} STREQUAL value)
+      message(STATUS "Found `${name}=${value}` as expected")
+    else ()
+      message(SEND_ERROR "Found `${name}=${value}` when it should have been ${expect_${name}}")
+    endif ()
+  endif ()
+endwhile ()
+
+if (expected_vars)
+  message(SEND_ERROR "Did not test expected variables: ${expected_vars}")
+endif ()
index 482cee8..00b254d 100644 (file)
@@ -1,49 +1,2 @@
-foreach(variant IN LISTS CMake_TEST_FindBLAS)
-  if(variant MATCHES "^([^.]+)\\.(.*)$")
-    set(vendor "${CMAKE_MATCH_1}")
-    set(alt_compiler "-DCMAKE_C_COMPILER=${CMAKE_MATCH_2}")
-  else()
-    set(vendor "${variant}")
-    set(alt_compiler "")
-  endif()
-  if(vendor STREQUAL "All" AND CMake_TEST_FindBLAS_All)
-    set(EXPECT_All "-DEXPECT_All=${CMake_TEST_FindBLAS_All}")
-  else()
-    set(EXPECT_All "")
-  endif()
-  add_test(NAME FindBLAS.Test_${variant} COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindBLAS/Test"
-    "${CMake_BINARY_DIR}/Tests/FindBLAS/Test_${variant}"
-    ${build_generator_args}
-    --build-project TestFindBLAS
-    --build-options ${build_options} ${alt_compiler} ${EXPECT_All} -DBLA_VENDOR=${vendor}
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-endforeach()
-
-foreach(variant IN LISTS CMake_TEST_FindBLAS_STATIC)
-  if(variant MATCHES "^([^.]+)\\.(.*)$")
-    set(vendor "${CMAKE_MATCH_1}")
-    set(alt_compiler "-DCMAKE_C_COMPILER=${CMAKE_MATCH_2}")
-  else()
-    set(vendor "${variant}")
-    set(alt_compiler "")
-  endif()
-  if(vendor STREQUAL "All" AND CMake_TEST_FindBLAS_STATIC_All)
-    set(EXPECT_All "-DEXPECT_All=${CMake_TEST_FindBLAS_STATIC_All}")
-  else()
-    set(EXPECT_All "")
-  endif()
-  add_test(NAME FindBLAS.Test_${variant}_Static COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindBLAS/Test"
-    "${CMake_BINARY_DIR}/Tests/FindBLAS/Test_${variant}_Static"
-    ${build_generator_args}
-    --build-project TestFindBLAS
-    --build-options ${build_options} ${alt_compiler} ${EXPECT_All} -DBLA_VENDOR=${vendor} -DBLA_STATIC=ON
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-endforeach()
+include("${CMake_SOURCE_DIR}/Tests/FindBLAS/add_BLAS_LAPACK_tests.cmake")
+add_BLAS_LAPACK_tests(CMake_TEST_FindBLAS)
index 7379749..14bf19f 100644 (file)
@@ -4,12 +4,18 @@ include(CTest)
 
 find_package(BLAS REQUIRED)
 
+if(NOT BLA_SIZEOF_INTEGER)
+  set(BLA_SIZEOF_INTEGER 4)
+endif()
+
 add_executable(test_tgt main.c)
 target_link_libraries(test_tgt BLAS::BLAS)
+target_compile_definitions(test_tgt PUBLIC BLA_SIZEOF_INTEGER=${BLA_SIZEOF_INTEGER})
 add_test(NAME test_tgt COMMAND test_tgt)
 
 add_executable(test_var main.c)
 target_link_libraries(test_var PRIVATE ${BLAS_LIBRARIES})
+target_compile_definitions(test_var PUBLIC BLA_SIZEOF_INTEGER=${BLA_SIZEOF_INTEGER})
 add_test(NAME test_var COMMAND test_var)
 
 if((BLA_VENDOR STREQUAL "Intel10_64lp") OR
@@ -17,4 +23,9 @@ if((BLA_VENDOR STREQUAL "Intel10_64lp") OR
   if(NOT BLAS_LIBRARIES MATCHES "^(-Wl,--start-group;)?[^;]*mkl_intel_lp64")
     message(FATAL_ERROR "BLAS_LIBRARIES does not start in mkl_intel_lp64:\n ${BLAS_LIBRARIES}")
   endif()
+elseif((BLA_VENDOR STREQUAL "Intel10_64ilp") OR
+   (BLA_VENDOR STREQUAL "All" AND EXPECT_All STREQUAL "Intel10_64ilp"))
+  if(NOT BLAS_LIBRARIES MATCHES "^(-Wl,--start-group;)?[^;]*mkl_intel_ilp64")
+    message(FATAL_ERROR "BLAS_LIBRARIES does not start in mkl_intel_ilp64:\n ${BLAS_LIBRARIES}")
+  endif()
 endif()
index e61b02c..4fc9fe4 100644 (file)
@@ -1,16 +1,25 @@
 #include <assert.h>
+#include <stdint.h>
 #include <string.h>
 
+#if BLA_SIZEOF_INTEGER == 4
+typedef int32_t blas_int;
+#elif BLA_SIZEOF_INTEGER == 8
+typedef int64_t blas_int;
+#else
+#  error BLA_SIZEOF_INTEGER is not declared!
+#endif
+
 // declare what parts of the blas C-API we need
-void dswap_(int* N, double* X, int* incX, double* Y, int* incY);
+void dswap_(blas_int* N, double* X, blas_int* incX, double* Y, blas_int* incY);
 
 int main()
 {
   double x[4] = { 1, 2, 3, 4 };
   double y[4] = { 8, 7, 7, 6 };
-  int N = 4;
-  int incX = 1;
-  int incY = 1;
+  blas_int N = 4;
+  blas_int incX = 1;
+  blas_int incY = 1;
   dswap_(&N, x, &incX, y, &incY);
   return 0;
 }
diff --git a/Tests/FindBLAS/add_BLAS_LAPACK_tests.cmake b/Tests/FindBLAS/add_BLAS_LAPACK_tests.cmake
new file mode 100644 (file)
index 0000000..42fe386
--- /dev/null
@@ -0,0 +1,53 @@
+function(add_BLAS_LAPACK_tests var)
+  if(var MATCHES "^CMake_TEST_Find(BLAS|LAPACK)$")
+    set(package "${CMAKE_MATCH_1}")
+  else()
+    message(FATAL_ERROR "Test list variable '${var}' not supported.")
+  endif()
+
+  set(all "")
+  set(compiler "")
+  set(model "")
+  set(static "")
+
+  set(sizeof_int_lp64 4)
+  set(sizeof_int_ilp64 8)
+
+  foreach(variant IN LISTS ${var})
+    if(variant MATCHES "^(all|compiler|model|static)=(.*)$")
+      set("${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}")
+      continue()
+    elseif(variant MATCHES "^([^=]+)=(.*)$")
+      message(FATAL_ERROR "Unknown variable '${variant}'")
+    endif()
+    set(variant_name "${variant}")
+    set(variant_options "-DBLA_VENDOR=${variant}")
+    if(variant STREQUAL "All" AND all)
+      list(APPEND variant_options "-DEXPECT_All=${all}")
+    endif()
+    if(model)
+      if(NOT variant_name MATCHES "Intel10_64")
+        string(APPEND variant_name "_${model}")
+      endif()
+      list(APPEND variant_options "-DBLA_SIZEOF_INTEGER=${sizeof_int_${model}}")
+    endif()
+    if(compiler)
+      string(APPEND variant_name "_${compiler}")
+      list(APPEND variant_options "-DCMAKE_C_COMPILER=${compiler}")
+    endif()
+    if(static)
+      string(APPEND variant_name "_Static")
+      list(APPEND variant_options "-DBLA_STATIC=ON")
+    endif()
+    add_test(NAME Find${package}.Test_${variant_name} COMMAND
+      ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+      --build-and-test
+      "${CMake_SOURCE_DIR}/Tests/Find${package}/Test"
+      "${CMake_BINARY_DIR}/Tests/Find${package}/Test_${variant_name}"
+      ${build_generator_args}
+      --build-project TestFind${package}
+      --build-options ${build_options} ${variant_options}
+      --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+      )
+  endforeach()
+endfunction()
diff --git a/Tests/FindGLUT/CMakeLists.txt b/Tests/FindGLUT/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e75ec40
--- /dev/null
@@ -0,0 +1,9 @@
+add_test(NAME FindGLUT.Test COMMAND ${CMAKE_CTEST_COMMAND}
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindGLUT/Test"
+  "${CMake_BINARY_DIR}/Tests/FindGLUT/Test"
+  ${build_generator_args}
+  --build-project TestFindGLUT
+  --build-options ${build_options}
+  --test-command ${CMAKE_CTEST_COMMAND} -V
+  )
diff --git a/Tests/FindGLUT/Test/CMakeLists.txt b/Tests/FindGLUT/Test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0f4e536
--- /dev/null
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.21)
+project(TestFindGLUT C)
+include(CTest)
+
+find_package(GLUT REQUIRED)
+
+add_executable(testglut_tgt main.c)
+target_link_libraries(testglut_tgt GLUT::GLUT)
+add_test(NAME testglut_tgt COMMAND testglut_tgt)
+
+add_executable(testglut_var main.c)
+target_include_directories(testglut_var PRIVATE ${GLUT_INCLUDE_DIRS})
+target_link_libraries(testglut_var PRIVATE ${GLUT_LIBRARIES})
+add_test(NAME testglut_var COMMAND testglut_var)
+
+set_tests_properties(testglut_tgt testglut_var
+    PROPERTIES WILL_FAIL true)
diff --git a/Tests/FindGLUT/Test/main.c b/Tests/FindGLUT/Test/main.c
new file mode 100644 (file)
index 0000000..1c8569c
--- /dev/null
@@ -0,0 +1,11 @@
+#include <GL/glut.h>
+#include <stdio.h>
+
+int main()
+{
+  /* The following should call exit(1) and print
+      freeglut  ERROR:  Function <glutCreateWindow> called
+      without first calling 'glutInit'.
+    to stderr */
+  glutCreateWindow("gluttest");
+}
diff --git a/Tests/FindJasper/CMakeLists.txt b/Tests/FindJasper/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1bfae78
--- /dev/null
@@ -0,0 +1,10 @@
+add_test(NAME FindJasper.Test COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindJasper/Test"
+  "${CMake_BINARY_DIR}/Tests/FindJasper/Test"
+  ${build_generator_args}
+  --build-project TestFindJasper
+  --build-options ${build_options}
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
diff --git a/Tests/FindJasper/Test/CMakeLists.txt b/Tests/FindJasper/Test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1e9467d
--- /dev/null
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.21)
+project(TestFindJasper C)
+include(CTest)
+
+find_package(Jasper)
+
+add_definitions(-DCMAKE_EXPECTED_JASPER_VERSION=${JASPER_VERSION_STRING})
+
+add_executable(test_jasper_tgt main.c)
+target_link_libraries(test_jasper_tgt Jasper::Jasper)
+add_test(NAME test_jasper_tgt COMMAND test_jasper_tgt)
+
+add_executable(test_jasper_var main.c)
+target_include_directories(test_jasper_var PRIVATE ${JASPER_INCLUDE_DIRS})
+target_link_libraries(test_jasper_var PRIVATE ${JASPER_LIBRARIES})
+add_test(NAME test_jasper_var COMMAND test_jasper_var)
diff --git a/Tests/FindJasper/Test/main.c b/Tests/FindJasper/Test/main.c
new file mode 100644 (file)
index 0000000..771344d
--- /dev/null
@@ -0,0 +1,17 @@
+#include <assert.h>
+// clang-format off
+#include <stdio.h>
+#include <jasper/jasper.h>
+// clang-format on
+
+int main()
+{
+  /* Without any JPEG file to open, test that the call fails as
+     expected.  This tests that linking worked. */
+  jas_init();
+  jas_image_t* img = jas_image_create0();
+  jas_image_destroy(img);
+  jas_cleanup();
+
+  return (JAS_VERSION != CMAKE_EXPECTED_JASPER_VERSION);
+}
index 535c7b6..a2470ef 100644 (file)
@@ -1,49 +1,2 @@
-foreach(variant IN LISTS CMake_TEST_FindLAPACK)
-  if(variant MATCHES "^([^.]+)\\.(.*)$")
-    set(vendor "${CMAKE_MATCH_1}")
-    set(alt_compiler "-DCMAKE_C_COMPILER=${CMAKE_MATCH_2}")
-  else()
-    set(vendor "${variant}")
-    set(alt_compiler "")
-  endif()
-  if(vendor STREQUAL "All" AND CMake_TEST_FindLAPACK_All)
-    set(EXPECT_All "-DEXPECT_All=${CMake_TEST_FindLAPACK_All}")
-  else()
-    set(EXPECT_All "")
-  endif()
-  add_test(NAME FindLAPACK.Test_${variant} COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindLAPACK/Test"
-    "${CMake_BINARY_DIR}/Tests/FindLAPACK/Test_${variant}"
-    ${build_generator_args}
-    --build-project TestFindLAPACK
-    --build-options ${build_options} ${alt_compiler} ${EXPECT_All} -DBLA_VENDOR=${vendor}
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-endforeach()
-
-foreach(variant IN LISTS CMake_TEST_FindLAPACK_STATIC)
-  if(variant MATCHES "^([^.]+)\\.(.*)$")
-    set(vendor "${CMAKE_MATCH_1}")
-    set(alt_compiler "-DCMAKE_C_COMPILER=${CMAKE_MATCH_2}")
-  else()
-    set(vendor "${variant}")
-    set(alt_compiler "")
-  endif()
-  if(vendor STREQUAL "All" AND CMake_TEST_FindLAPACK_STATIC_All)
-    set(EXPECT_All "-DEXPECT_All=${CMake_TEST_FindLAPACK_STATIC_All}")
-  else()
-    set(EXPECT_All "")
-  endif()
-  add_test(NAME FindLAPACK.Test_${variant}_Static COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindLAPACK/Test"
-    "${CMake_BINARY_DIR}/Tests/FindLAPACK/Test_${variant}_Static"
-    ${build_generator_args}
-    --build-project TestFindLAPACK
-    --build-options ${build_options} ${alt_compiler} ${EXPECT_All} -DBLA_VENDOR=${vendor} -DBLA_STATIC=ON
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-endforeach()
+include("${CMake_SOURCE_DIR}/Tests/FindBLAS/add_BLAS_LAPACK_tests.cmake")
+add_BLAS_LAPACK_tests(CMake_TEST_FindLAPACK)
index 23a43ac..f5d5a73 100644 (file)
@@ -4,12 +4,18 @@ include(CTest)
 
 find_package(LAPACK REQUIRED)
 
+if(NOT BLA_SIZEOF_INTEGER)
+  set(BLA_SIZEOF_INTEGER 4)
+endif()
+
 add_executable(test_tgt main.c)
 target_link_libraries(test_tgt LAPACK::LAPACK)
+target_compile_definitions(test_tgt PUBLIC BLA_SIZEOF_INTEGER=${BLA_SIZEOF_INTEGER})
 add_test(NAME test_tgt COMMAND test_tgt)
 
 add_executable(test_var main.c)
 target_link_libraries(test_var PRIVATE ${LAPACK_LIBRARIES})
+target_compile_definitions(test_var PUBLIC BLA_SIZEOF_INTEGER=${BLA_SIZEOF_INTEGER})
 add_test(NAME test_var COMMAND test_var)
 
 if((BLA_VENDOR STREQUAL "Intel10_64lp") OR
@@ -17,4 +23,9 @@ if((BLA_VENDOR STREQUAL "Intel10_64lp") OR
   if(NOT LAPACK_LIBRARIES MATCHES "^(-Wl,--start-group;)?[^;]*mkl_intel_lp64")
     message(FATAL_ERROR "LAPACK_LIBRARIES does not start in mkl_intel_lp64:\n ${LAPACK_LIBRARIES}")
   endif()
+elseif((BLA_VENDOR STREQUAL "Intel10_64ilp") OR
+   (BLA_VENDOR STREQUAL "All" AND EXPECT_All STREQUAL "Intel10_64ilp"))
+  if(NOT LAPACK_LIBRARIES MATCHES "^(-Wl,--start-group;)?[^;]*mkl_intel_ilp64")
+    message(FATAL_ERROR "LAPACK_LIBRARIES does not start in mkl_intel_ilp64:\n ${LAPACK_LIBRARIES}")
+  endif()
 endif()
index 5873e7b..dd33fb3 100644 (file)
@@ -1,8 +1,18 @@
 #include <assert.h>
+#include <stdint.h>
 #include <string.h>
 
+#if BLA_SIZEOF_INTEGER == 4
+typedef int32_t blas_int;
+#elif BLA_SIZEOF_INTEGER == 8
+typedef int64_t blas_int;
+#else
+#  error BLA_SIZEOF_INTEGER is not declared!
+#endif
+
 // declare what parts of the lapack C-API we need
-void dgesv_(int*, int*, double*, int*, int*, double*, int*, int*);
+void dgesv_(blas_int*, blas_int*, double*, blas_int*, blas_int*, double*,
+            blas_int*, blas_int*);
 
 int main()
 {
@@ -10,11 +20,11 @@ int main()
     0, 1, 2, 3, 4, 5, 6, 7,
   };
   double B[2] = { 0, 5 };
-  int ipiv[2] = { 0, 0 };
-  int info = 0;
+  blas_int ipiv[2] = { 0, 0 };
+  blas_int info = 0;
 
-  int dim = 2;
-  int numCols = 1;
+  blas_int dim = 2;
+  blas_int numCols = 1;
   dgesv_(&dim, &numCols, A, &dim, ipiv, B, &dim, &info);
   return 0;
 }
diff --git a/Tests/FindMatlab/targets_checks/CMakeLists.txt b/Tests/FindMatlab/targets_checks/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4af7cc3
--- /dev/null
@@ -0,0 +1,44 @@
+cmake_minimum_required (VERSION 2.8.12)
+enable_testing()
+project(targets_checks)
+
+set(MATLAB_FIND_DEBUG TRUE)
+
+if(NOT "${MCR_ROOT}" STREQUAL "")
+    set(Matlab_ROOT_DIR "${MCR_ROOT}")
+    if(NOT EXISTS "${MCR_ROOT}")
+        message(FATAL_ERROR "MCR does not exist ${MCR_ROOT}")
+    endif()
+endif()
+
+# 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 ENG_LIBRARY MAT_LIBRARY
+                    OPTIONAL_COMPONENTS MAIN_PROGRAM)
+
+if(NOT TARGET Matlab::mx)
+    message(FATAL_ERROR "Matlab::mx target does not exist")
+endif()
+
+if(NOT TARGET Matlab::mex)
+    message(FATAL_ERROR "Matlab::mex target does not exist")
+endif()
+
+if(NOT TARGET Matlab::eng)
+    message(FATAL_ERROR "Matlab::eng target does not exist")
+endif()
+
+if(NOT TARGET Matlab::mat)
+    message(FATAL_ERROR "Matlab::mat target does not exist")
+endif()
+
+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::mex
+    )
index d4c19c7..f00565e 100644 (file)
@@ -2,17 +2,26 @@ cmake_minimum_required (VERSION 2.6)
 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 AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") OR CMAKE_C_COMPILER_ID STREQUAL AppleClang)
+    OR (CMAKE_C_COMPILER_ID STREQUAL Clang AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+    OR CMAKE_C_COMPILER_ID STREQUAL NVHPC
+    OR CMAKE_C_COMPILER_ID STREQUAL AppleClang
+    OR ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC" AND
+       CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL "19.29.30036.3" AND
+       NOT CMAKE_GENERATOR MATCHES "Visual Studio")) # No support for VS generators yet.
     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)
-    # The Bullseye wrapper appears to break the -isystem effect.
-    execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE out ERROR_VARIABLE out)
-    if("x${out}" MATCHES "Bullseye")
-      set(run_sys_includes_test 0)
+  if ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC")
+    set(run_sys_includes_test 1)
+  else ()
+    include(CheckCXXCompilerFlag)
+    check_cxx_compiler_flag(-Wunused-variable run_sys_includes_test)
+    if(run_sys_includes_test)
+      # The Bullseye wrapper appears to break the -isystem effect.
+      execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE out ERROR_VARIABLE out)
+      if("x${out}" MATCHES "Bullseye")
+        set(run_sys_includes_test 0)
+      endif()
     endif()
   endif()
   if (run_sys_includes_test)
index dee39c8..a746a68 100644 (file)
@@ -6,9 +6,17 @@ project(SystemIncludeDirectories)
 add_library(systemlib systemlib.cpp)
 target_include_directories(systemlib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/systemlib")
 
+function (apply_error_flags target)
+  if (MSVC)
+    target_compile_options(${target} PRIVATE /we4101)
+  else ()
+    target_compile_options(${target} PRIVATE -Werror=unused-variable)
+  endif ()
+endfunction ()
+
 add_library(upstream upstream.cpp)
 target_link_libraries(upstream LINK_PUBLIC systemlib)
-target_compile_options(upstream PRIVATE -Werror=unused-variable)
+apply_error_flags(upstream)
 
 target_include_directories(upstream SYSTEM PUBLIC
   $<TARGET_PROPERTY:systemlib,INTERFACE_INCLUDE_DIRECTORIES>
@@ -29,7 +37,7 @@ endif()
 
 add_library(consumer consumer.cpp)
 target_link_libraries(consumer upstream config_specific)
-target_compile_options(consumer PRIVATE -Werror=unused-variable)
+apply_error_flags(consumer)
 
 add_library(iface IMPORTED INTERFACE)
 set_property(TARGET iface PROPERTY INTERFACE_INCLUDE_DIRECTORIES
@@ -38,21 +46,21 @@ set_property(TARGET iface PROPERTY INTERFACE_INCLUDE_DIRECTORIES
 
 add_library(imported_consumer imported_consumer.cpp)
 target_link_libraries(imported_consumer iface)
-target_compile_options(imported_consumer PRIVATE -Werror=unused-variable)
+apply_error_flags(imported_consumer)
 
 add_library(imported_consumer2 imported_consumer.cpp)
 target_link_libraries(imported_consumer2 imported_consumer)
-target_compile_options(imported_consumer2 PRIVATE -Werror=unused-variable)
+apply_error_flags(imported_consumer2)
 
 # add a target which has a relative system include
 add_library(somelib imported_consumer.cpp)
 target_include_directories(somelib SYSTEM PUBLIC "systemlib_header_only")
-target_compile_options(somelib PRIVATE -Werror=unused-variable)
+apply_error_flags(somelib)
 
 # add a target which consumes a relative system include
 add_library(otherlib upstream.cpp)
 target_link_libraries(otherlib PUBLIC somelib)
-target_compile_options(somelib PRIVATE -Werror=unused-variable)
+apply_error_flags(otherlib)
 
 macro(do_try_compile error_option)
   set(TC_ARGS
@@ -61,7 +69,11 @@ macro(do_try_compile error_option)
     LINK_LIBRARIES iface
   )
   if (${error_option} STREQUAL WITH_ERROR)
-    list(APPEND TC_ARGS COMPILE_DEFINITIONS -Werror=unused-variable)
+    if (MSVC)
+      list(APPEND TC_ARGS COMPILE_DEFINITIONS /we4101)
+    else ()
+      list(APPEND TC_ARGS COMPILE_DEFINITIONS -Werror=unused-variable)
+    endif ()
   endif()
   try_compile(${TC_ARGS})
 endmacro()
index a670c2a..3daf69e 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef UPSTREAM_H
 #define UPSTREAM_H
 
-#include "systemlib.h"
+#include <systemlib.h>
 
 #ifdef _WIN32
 __declspec(dllexport)
index 70dfa01..5d58633 100644 (file)
@@ -7,14 +7,14 @@ set_target_properties(c_interface PROPERTIES
   INTERFACE_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}>"
   INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}>"
 )
-target_compile_options(c_interface INTERFACE "$<$<COMPILE_LANG_AND_ID:C,GNU,Clang>:-Werror=unused-variable>")
+target_compile_options(c_interface INTERFACE "$<$<COMPILE_LANG_AND_ID:C,GNU,Clang>:-Werror=unused-variable>;$<$<COMPILE_LANG_AND_ID:C,MSVC>:/we4101>")
 
 add_library(cxx_interface INTERFACE)
 set_target_properties(cxx_interface PROPERTIES
   INTERFACE_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_system_include>"
   INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_system_include>"
 )
-target_compile_options(cxx_interface INTERFACE "$<$<COMPILE_LANG_AND_ID:CXX,GNU,Clang>:-Werror=unused-variable>")
+target_compile_options(cxx_interface INTERFACE "$<$<COMPILE_LANG_AND_ID:CXX,GNU,Clang>:-Werror=unused-variable>;$<$<COMPILE_LANG_AND_ID:C,MSVC>:/we4101>")
 
 # The C header must come before the C++ header for this test to smoke out the
 # failure. The order of sources is how CMake determines the include cache
diff --git a/Tests/InstallMode/CMakeLists.txt b/Tests/InstallMode/CMakeLists.txt
new file mode 100644 (file)
index 0000000..96c83a0
--- /dev/null
@@ -0,0 +1,124 @@
+cmake_minimum_required(VERSION 3.20.0)
+
+project(superpro LANGUAGES NONE)
+
+add_subdirectory(superpro)
+
+include(Subproject.cmake)
+add_subproject(static_lib   DIR subpro_a_static_lib)
+add_subproject(shared_lib   DIR subpro_b_shared_lib)
+add_subproject(nested_lib   DIR subpro_c_nested_lib NO_INSTALL)
+add_subproject(executable   DIR subpro_d_executable
+  DEPENDS
+    static_lib
+    shared_lib
+    nested_lib
+)
+
+include(CTest)
+if(BUILD_TESTING)
+  enable_language(CXX)  # required by GNUInstallDirs
+  include(GNUInstallDirs)
+
+  macro(testme _name _path _symlink)
+    add_test(
+      NAME "${_name}"
+      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+      COMMAND
+        "${CMAKE_COMMAND}"
+        "-DFILE_PATH=${CMAKE_INSTALL_PREFIX}/${_path}"
+        "-DEXPECT_SYMLINK:BOOL=${_symlink}"
+        "-DEXPECT_ABSOLUTE:BOOL=${ARGN}"
+        "-P" "${CMAKE_SOURCE_DIR}/Test.cmake"
+    )
+  endmacro()
+
+  set(_mode $ENV{CMAKE_INSTALL_MODE})
+  if(NOT "${_mode}" OR "${_mode}" STREQUAL "COPY")
+    set(expect_symlink NO)
+  elseif("${_mode}" MATCHES "(REL_)?SYMLINK(_OR_COPY)?")
+    set(expect_symlink YES)
+    set(expect_absolute NO)
+  elseif("${_mode}" MATCHES "ABS_SYMLINK(_OR_COPY)?")
+    set(expect_symlink YES)
+    set(expect_absolute YES)
+  endif()
+
+  # toplevel project should respect CMAKE_INSTALL_MODE
+
+  testme(superproj_file_copy
+    "file_copy.txt" NO)
+  testme(superproj_file_copy_file
+    "file_copy_file.txt" NO)
+  testme(superproj_file_install
+    "file_install.txt"
+    ${expect_symlink}
+    ${expect_absolute})
+  testme(superproj_file_create_link_symbolic
+    "file_create_link_symbolic.txt" YES YES)
+
+  # subprojects should receive and respect CMAKE_INSTALL_MODE too
+
+  testme(subpro_a_static_lib_header
+    "${CMAKE_INSTALL_INCLUDEDIR}/static_lib.h"
+    ${expect_symlink}
+    ${expect_absolute}
+  )
+  testme(subpro_a_static_lib_libfile
+    "${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}the_static_lib${CMAKE_STATIC_LIBRARY_SUFFIX}"
+    ${expect_symlink}
+    ${expect_absolute}
+  )
+
+  testme(subpro_b_shared_lib_header
+    "${CMAKE_INSTALL_INCLUDEDIR}/shared_lib.h"
+    ${expect_symlink}
+    ${expect_absolute}
+  )
+
+  if(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG AND
+      "${CMAKE_CXX_CREATE_SHARED_MODULE}" MATCHES "SONAME_FLAG")
+    # due to semver, this is always a link
+    testme(subpro_b_shared_lib_libfile
+      "${CMAKE_INSTALL_LIBDIR}/${CMAKE_SHARED_LIBRARY_PREFIX}the_shared_lib${CMAKE_SHARED_LIBRARY_SUFFIX}"
+      YES
+      ${expect_absolute}
+    )
+    # this is the actual shared lib, so should follow CMAKE_INSTALL_MODE rules
+    testme(subpro_b_shared_lib_libfile_versuffix
+      "${CMAKE_INSTALL_LIBDIR}/${CMAKE_SHARED_LIBRARY_PREFIX}the_shared_lib${CMAKE_SHARED_LIBRARY_SUFFIX}.2.3.4"
+      ${expect_symlink}
+      ${expect_absolute}
+    )
+  endif()
+
+  testme(subpro_d_executable_exefile
+    "${CMAKE_INSTALL_BINDIR}/the_executable${CMAKE_EXECUTABLE_SUFFIX}"
+    ${expect_symlink}
+    ${expect_absolute}
+  )
+
+  # nested subprojects should receive and respect CMAKE_INSTALL_MODE too
+
+  testme(subsubpro_c1_header
+    "${CMAKE_INSTALL_INCLUDEDIR}/c1_lib.h"
+    ${expect_symlink}
+    ${expect_absolute}
+  )
+  testme(subsubpro_c1_libfile
+    "${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}the_c1_lib${CMAKE_STATIC_LIBRARY_SUFFIX}"
+    ${expect_symlink}
+    ${expect_absolute}
+  )
+
+  testme(subsubpro_c2_header
+    "${CMAKE_INSTALL_INCLUDEDIR}/c2_lib.h"
+    ${expect_symlink}
+    ${expect_absolute}
+  )
+  testme(subsubpro_c2_libfile
+    "${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}the_c2_lib${CMAKE_STATIC_LIBRARY_SUFFIX}"
+    ${expect_symlink}
+    ${expect_absolute}
+  )
+endif()
diff --git a/Tests/InstallMode/README.txt b/Tests/InstallMode/README.txt
new file mode 100644 (file)
index 0000000..a4316eb
--- /dev/null
@@ -0,0 +1,43 @@
+This is an example superbuild project to demonstrate the use of the
+CMAKE_INSTALL_MODE environment variable on.
+
+The project hierarchy is like (B = Builds / D = Link Dependency):
+
++---------------------------------------------------------------------+
+|                           Superbuild (Top)                          |
++---------------------------------------------------------------------+
+        |                 |                 |                 |
+        |                 |                 |                 |
+       (B)               (B)               (B)               (B)
+        |                 |                 |                 |
+        v                 v                 v                 v
++---------------+ +---------------+ +---------------+ +---------------+
+| A: Static Lib | | B: Shared Lib | | C: Nested     | | D: Executable |
+|    Project    | |    Project    | |    Superbuild | |    Project    |
++---------------+ +---------------+ +---------------+ +---------------+
+        ^               ^               |       |        |   |   |
+        |               |              (B)     (B)       |   |   |
+        |               |               |       |        |   |   |
+        |               |               v       |        |   |   |
+        |               |  +----------------+   |        |   |   |
+        |               |  | C1: Static Lib |   |        |   |   |
+        |               |  |     Project    |   |       (D) (D) (D)
+        |               |  +----------------+   |        |   |   |
+        |               |       ^               |        |   |   |
+        |               |       |               v        |   |   |
+        |               |      (D) +----------------+    |   |   |
+        |               |       |  | C2: Static Lib |<---+   |   |
+        |               |       +--|     Project    |        |   |
+        |               |          +----------------+        |   |
+        |               |                                    |   |
+        |               +------------------------------------+   |
+        |                                                        |
+        +--------------------------------------------------------+
+
+The superbuild system is built on top of ExternalProject_Add().
+
+NOTE that the subprojects will configure, build and install
+during the build phase ('make') of the top-level project.
+There is no install target in the top-level project!
+The CMAKE_INSTALL_PREFIX is therefore populated during the build
+phase already.
diff --git a/Tests/InstallMode/Subproject.cmake b/Tests/InstallMode/Subproject.cmake
new file mode 100644 (file)
index 0000000..826e61e
--- /dev/null
@@ -0,0 +1,73 @@
+include(ExternalProject)
+
+# add_subproject(<name> [NO_INSTALL] [DIR <dirname>] [DEPENDS [subpro_dep ...]])
+function(add_subproject _name)
+  cmake_parse_arguments(_arg "NO_INSTALL" "DIR" "DEPENDS" ${ARGN})
+
+  if(_arg_UNPARSED_ARGUMENTS)
+    message(FATAL_ERROR "There are unparsed arguments")
+  endif()
+
+  set(_maybe_NO_INSTALL)
+  if(_arg_NO_INSTALL)
+    set(_maybe_NO_INSTALL INSTALL_COMMAND "")
+  endif()
+
+  if(CMAKE_GENERATOR MATCHES "Ninja Multi-Config")
+    # Replace list separator before passing on to ExternalProject_Add
+    string(REPLACE ";" "|" _CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}")
+    string(REPLACE ";" "|" _CROSS_CONFIGS "${CMAKE_CROSS_CONFIGS}")
+    string(REPLACE ";" "|" _DEFAULT_CONFIGS "${CMAKE_DEFAULT_CONFIGS}")
+
+    set(_maybe_NINJA_MULTICONFIG_ARGS
+      "-DCMAKE_CONFIGURATION_TYPES:STRINGS=${_CONFIGURATION_TYPES}"
+      "-DCMAKE_CROSS_CONFIGS:STRINGS=${_CROSS_CONFIGS}"
+      "-DCMAKE_DEFAULT_BUILD_TYPE:STRING=${CMAKE_DEFAULT_BUILD_TYPE}"
+      "-DCMAKE_DEFAULT_CONFIGS:STRINGS=${_DEFAULT_CONFIGS}"
+    )
+  endif()
+
+  ExternalProject_Add("${_name}"
+    DOWNLOAD_COMMAND      ""
+    UPDATE_COMMAND        ""
+    UPDATE_DISCONNECTED   ON
+
+    "${_maybe_NO_INSTALL}"
+
+    BUILD_ALWAYS          ON
+
+    LOG_DOWNLOAD          OFF
+    LOG_UPDATE            OFF
+    LOG_PATCH             OFF
+    LOG_CONFIGURE         OFF
+    LOG_BUILD             OFF
+    LOG_INSTALL           OFF
+
+    SOURCE_DIR            "${PROJECT_SOURCE_DIR}/${_arg_DIR}"
+
+    # Private build directory per subproject
+    BINARY_DIR            "${PROJECT_BINARY_DIR}/subproject/${_arg_DIR}"
+
+    # Common install directory, populated immediately
+    # during build (during build - not install - of superproject)
+    INSTALL_DIR           "${CMAKE_INSTALL_PREFIX}"
+
+    DEPENDS
+      ${_arg_DEPENDS}
+
+    LIST_SEPARATOR "|"
+    CMAKE_ARGS
+      "-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>"
+
+      # We can rely on ExternalProject to pick the right
+      # generator (and architecture/toolset where applicable),
+      # however, we need to explicitly inherit other parent
+      # project's build settings.
+      "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}"
+      "${_maybe_NINJA_MULTICONFIG_ARGS}"
+
+      # Subproject progress reports clutter up the output, disable
+      "-DCMAKE_TARGET_MESSAGES:BOOL=OFF"
+      "-DCMAKE_RULE_MESSAGES:BOOL=OFF"
+  )
+endfunction()
diff --git a/Tests/InstallMode/Test.cmake b/Tests/InstallMode/Test.cmake
new file mode 100644 (file)
index 0000000..46c8fa1
--- /dev/null
@@ -0,0 +1,38 @@
+message("Testing...")
+message("FILE_PATH =       ${FILE_PATH}")
+message("EXPECT_SYMLINK =  ${EXPECT_SYMLINK}")
+message("EXPECT_ABSOLUTE = ${EXPECT_ABSOLUTE}")
+
+if(NOT DEFINED FILE_PATH)
+  message(FATAL_ERROR "FILE_PATH variable must be defined")
+endif()
+
+if(NOT EXISTS "${FILE_PATH}")
+  message(FATAL_ERROR "File ${FILE_PATH} does not exist")
+endif()
+
+if(NOT DEFINED EXPECT_SYMLINK)
+  message(FATAL_ERROR "EXPECT_SYMLINK must be defined")
+endif()
+
+if(EXPECT_SYMLINK)
+  if(NOT DEFINED EXPECT_ABSOLUTE)
+    message(FATAL_ERROR "EXPECT_ABSOLUTE variable must be defined")
+  endif()
+
+  if(NOT IS_SYMLINK "${FILE_PATH}")
+    message(FATAL_ERROR "${FILE_PATH} must be a symlink")
+  endif()
+
+  file(READ_SYMLINK "${FILE_PATH}" TARGET_PATH)
+
+  if(EXPECT_ABSOLUTE AND NOT IS_ABSOLUTE "${TARGET_PATH}")
+    message(FATAL_ERROR "${FILE_PATH} must be an absolute symlink")
+  elseif(NOT EXPECT_ABSOLUTE AND IS_ABSOLUTE "${TARGET_PATH}")
+    message(FATAL_ERROR "${FILE_PATH} must be a relative symlink")
+  endif()
+else()
+  if(IS_SYMLINK "${FILE_PATH}")
+    message(FATAL_ERROR "${FILE_PATH} must NOT be a symlink")
+  endif()
+endif()
diff --git a/Tests/InstallMode/subpro_a_static_lib/CMakeLists.txt b/Tests/InstallMode/subpro_a_static_lib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7cd32cc
--- /dev/null
@@ -0,0 +1,60 @@
+# This CMakeLists.txt is part of the subproject A (ExternalProject_Add).
+
+cmake_minimum_required(VERSION 3.20)
+project(static_lib_project VERSION 1.2.3 LANGUAGES CXX)
+
+include(GNUInstallDirs)
+
+add_library(the_static_lib STATIC
+  "include/static_lib.h"
+  "src/static_lib.cpp"
+)
+
+target_include_directories(the_static_lib PUBLIC
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+install(
+  DIRECTORY   "${CMAKE_CURRENT_SOURCE_DIR}/include/"
+  DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+
+install(
+  TARGETS
+    the_static_lib
+  EXPORT main
+  ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+  LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+)
+
+set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+
+include(CMakePackageConfigHelpers)
+
+configure_package_config_file(
+  "cmake/PackageConfig.cmake.in"
+  "${PROJECT_NAME}Config.cmake"
+  INSTALL_DESTINATION "${INSTALL_CMAKE_DIR}"
+  PATH_VARS
+    CMAKE_INSTALL_INCLUDEDIR
+    CMAKE_INSTALL_LIBDIR
+)
+
+write_basic_package_version_file("${PROJECT_NAME}Version.cmake"
+  VERSION       "${PROJECT_VERSION}"
+  COMPATIBILITY SameMajorVersion
+)
+
+install(
+  EXPORT      main
+  FILE        "${PROJECT_NAME}Targets.cmake"
+  DESTINATION "${INSTALL_CMAKE_DIR}"
+)
+
+install(
+  FILES
+    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Version.cmake"
+  DESTINATION "${INSTALL_CMAKE_DIR}"
+)
diff --git a/Tests/InstallMode/subpro_a_static_lib/cmake/PackageConfig.cmake.in b/Tests/InstallMode/subpro_a_static_lib/cmake/PackageConfig.cmake.in
new file mode 100644 (file)
index 0000000..0fe72c9
--- /dev/null
@@ -0,0 +1,8 @@
+set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
+
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+
+set_and_check(@PROJECT_NAME@_INCLUDE_DIR  "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
+set_and_check(@PROJECT_NAME@_LIB_DIR      "@PACKAGE_CMAKE_INSTALL_LIBDIR@")
diff --git a/Tests/InstallMode/subpro_a_static_lib/include/static_lib.h b/Tests/InstallMode/subpro_a_static_lib/include/static_lib.h
new file mode 100644 (file)
index 0000000..bd82d2e
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once
+
+void static_hello();
diff --git a/Tests/InstallMode/subpro_a_static_lib/src/static_lib.cpp b/Tests/InstallMode/subpro_a_static_lib/src/static_lib.cpp
new file mode 100644 (file)
index 0000000..fe1cd85
--- /dev/null
@@ -0,0 +1,10 @@
+#include <iostream>
+
+#include <static_lib.h>
+
+using namespace std;
+
+void static_hello()
+{
+  cout << "Hello from static_lib" << endl;
+}
diff --git a/Tests/InstallMode/subpro_b_shared_lib/CMakeLists.txt b/Tests/InstallMode/subpro_b_shared_lib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b3d9cb2
--- /dev/null
@@ -0,0 +1,75 @@
+# This CMakeLists.txt is part of the subproject B (ExternalProject_Add).
+
+cmake_minimum_required(VERSION 3.20)
+project(shared_lib_project VERSION 2.3.4 LANGUAGES CXX)
+
+include(GNUInstallDirs)
+include(GenerateExportHeader)
+
+add_library(the_shared_lib SHARED
+  "include/shared_lib.h"
+  "src/shared_lib.cpp"
+)
+
+generate_export_header(the_shared_lib
+  BASE_NAME shared_lib
+  EXPORT_FILE_NAME include/shared_lib_export.h
+)
+
+set_target_properties(the_shared_lib
+  PROPERTIES
+    VERSION   "${PROJECT_VERSION}"
+    SOVERSION "${PROJECT_VERSION}"
+)
+
+target_include_directories(the_shared_lib PUBLIC
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
+  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+install(
+  DIRECTORY
+    "${CMAKE_CURRENT_SOURCE_DIR}/include/"
+    "${CMAKE_CURRENT_BINARY_DIR}/include/"
+  DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+
+install(
+  TARGETS
+    the_shared_lib
+  EXPORT main
+  ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+  LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+)
+
+set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+
+include(CMakePackageConfigHelpers)
+
+configure_package_config_file(
+  "cmake/PackageConfig.cmake.in"
+  "${PROJECT_NAME}Config.cmake"
+  INSTALL_DESTINATION "${INSTALL_CMAKE_DIR}"
+  PATH_VARS
+    CMAKE_INSTALL_INCLUDEDIR
+    CMAKE_INSTALL_LIBDIR
+)
+
+write_basic_package_version_file("${PROJECT_NAME}Version.cmake"
+  VERSION       "${PROJECT_VERSION}"
+  COMPATIBILITY SameMajorVersion
+)
+
+install(
+  EXPORT      main
+  FILE        "${PROJECT_NAME}Targets.cmake"
+  DESTINATION "${INSTALL_CMAKE_DIR}"
+)
+
+install(
+  FILES
+    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Version.cmake"
+  DESTINATION "${INSTALL_CMAKE_DIR}"
+)
diff --git a/Tests/InstallMode/subpro_b_shared_lib/cmake/PackageConfig.cmake.in b/Tests/InstallMode/subpro_b_shared_lib/cmake/PackageConfig.cmake.in
new file mode 100644 (file)
index 0000000..0fe72c9
--- /dev/null
@@ -0,0 +1,8 @@
+set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
+
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+
+set_and_check(@PROJECT_NAME@_INCLUDE_DIR  "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
+set_and_check(@PROJECT_NAME@_LIB_DIR      "@PACKAGE_CMAKE_INSTALL_LIBDIR@")
diff --git a/Tests/InstallMode/subpro_b_shared_lib/include/shared_lib.h b/Tests/InstallMode/subpro_b_shared_lib/include/shared_lib.h
new file mode 100644 (file)
index 0000000..550b2b4
--- /dev/null
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <shared_lib_export.h>
+
+void SHARED_LIB_EXPORT shared_hello();
diff --git a/Tests/InstallMode/subpro_b_shared_lib/src/shared_lib.cpp b/Tests/InstallMode/subpro_b_shared_lib/src/shared_lib.cpp
new file mode 100644 (file)
index 0000000..2820d5d
--- /dev/null
@@ -0,0 +1,10 @@
+#include <iostream>
+
+#include <shared_lib.h>
+
+using namespace std;
+
+void shared_hello()
+{
+  cout << "Hello from shared_lib" << endl;
+}
diff --git a/Tests/InstallMode/subpro_c_nested_lib/CMakeLists.txt b/Tests/InstallMode/subpro_c_nested_lib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e397c02
--- /dev/null
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.20.0)
+
+project(subpro_c_nested_lib LANGUAGES NONE)
+
+include(../Subproject.cmake)
+add_subproject(c1_lib   DIR subsubpro_c1_lib)
+add_subproject(c2_lib   DIR subsubpro_c2_lib
+  DEPENDS
+    c1_lib
+)
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/CMakeLists.txt b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..89f3755
--- /dev/null
@@ -0,0 +1,61 @@
+# This CMakeLists.txt is a nested subproject of the
+# subproject C (ExternalProject_Add).
+
+cmake_minimum_required(VERSION 3.20)
+project(c1_lib_project VERSION 1.2.3 LANGUAGES CXX)
+
+include(GNUInstallDirs)
+
+add_library(the_c1_lib STATIC
+  "include/c1_lib.h"
+  "src/c1_lib.cpp"
+)
+
+target_include_directories(the_c1_lib PUBLIC
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+install(
+  DIRECTORY   "${CMAKE_CURRENT_SOURCE_DIR}/include/"
+  DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+
+install(
+  TARGETS
+    the_c1_lib
+  EXPORT main
+  ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+  LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+)
+
+set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+
+include(CMakePackageConfigHelpers)
+
+configure_package_config_file(
+  "cmake/PackageConfig.cmake.in"
+  "${PROJECT_NAME}Config.cmake"
+  INSTALL_DESTINATION "${INSTALL_CMAKE_DIR}"
+  PATH_VARS
+    CMAKE_INSTALL_INCLUDEDIR
+    CMAKE_INSTALL_LIBDIR
+)
+
+write_basic_package_version_file("${PROJECT_NAME}Version.cmake"
+  VERSION       "${PROJECT_VERSION}"
+  COMPATIBILITY SameMajorVersion
+)
+
+install(
+  EXPORT      main
+  FILE        "${PROJECT_NAME}Targets.cmake"
+  DESTINATION "${INSTALL_CMAKE_DIR}"
+)
+
+install(
+  FILES
+    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Version.cmake"
+  DESTINATION "${INSTALL_CMAKE_DIR}"
+)
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/cmake/PackageConfig.cmake.in b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/cmake/PackageConfig.cmake.in
new file mode 100644 (file)
index 0000000..0fe72c9
--- /dev/null
@@ -0,0 +1,8 @@
+set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
+
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+
+set_and_check(@PROJECT_NAME@_INCLUDE_DIR  "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
+set_and_check(@PROJECT_NAME@_LIB_DIR      "@PACKAGE_CMAKE_INSTALL_LIBDIR@")
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/include/c1_lib.h b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/include/c1_lib.h
new file mode 100644 (file)
index 0000000..245f9d4
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once
+
+void c1_hello();
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/src/c1_lib.cpp b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c1_lib/src/c1_lib.cpp
new file mode 100644 (file)
index 0000000..c405056
--- /dev/null
@@ -0,0 +1,10 @@
+#include <iostream>
+
+#include <c1_lib.h>
+
+using namespace std;
+
+void c1_hello()
+{
+  cout << "Hello from c1_lib" << endl;
+}
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/CMakeLists.txt b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7580c77
--- /dev/null
@@ -0,0 +1,71 @@
+# This CMakeLists.txt is a nested subproject of the
+# subproject C (ExternalProject_Add).
+
+cmake_minimum_required(VERSION 3.20)
+project(c2_lib_project VERSION 1.2.3 LANGUAGES CXX)
+
+find_package(c1_lib_project REQUIRED)
+
+include(GNUInstallDirs)
+
+add_library(the_c2_lib STATIC
+  "include/c2_lib.h"
+  "src/c2_lib.cpp"
+)
+
+target_link_libraries(the_c2_lib
+  PUBLIC
+    the_c1_lib
+)
+
+# This is to fix an issue on AIX/GCC (see commit 4fc47424)
+set_property(TARGET the_c2_lib PROPERTY NO_SYSTEM_FROM_IMPORTED 1)
+
+target_include_directories(the_c2_lib PUBLIC
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+install(
+  DIRECTORY   "${CMAKE_CURRENT_SOURCE_DIR}/include/"
+  DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+
+install(
+  TARGETS
+    the_c2_lib
+  EXPORT main
+  ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+  LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+)
+
+set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+
+include(CMakePackageConfigHelpers)
+
+configure_package_config_file(
+  "cmake/PackageConfig.cmake.in"
+  "${PROJECT_NAME}Config.cmake"
+  INSTALL_DESTINATION "${INSTALL_CMAKE_DIR}"
+  PATH_VARS
+    CMAKE_INSTALL_INCLUDEDIR
+    CMAKE_INSTALL_LIBDIR
+)
+
+write_basic_package_version_file("${PROJECT_NAME}Version.cmake"
+  VERSION       "${PROJECT_VERSION}"
+  COMPATIBILITY SameMajorVersion
+)
+
+install(
+  EXPORT      main
+  FILE        "${PROJECT_NAME}Targets.cmake"
+  DESTINATION "${INSTALL_CMAKE_DIR}"
+)
+
+install(
+  FILES
+    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Version.cmake"
+  DESTINATION "${INSTALL_CMAKE_DIR}"
+)
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/cmake/PackageConfig.cmake.in b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/cmake/PackageConfig.cmake.in
new file mode 100644 (file)
index 0000000..45a177a
--- /dev/null
@@ -0,0 +1,11 @@
+set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
+
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+
+set_and_check(@PROJECT_NAME@_INCLUDE_DIR  "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
+set_and_check(@PROJECT_NAME@_LIB_DIR      "@PACKAGE_CMAKE_INSTALL_LIBDIR@")
+
+include(CMakeFindDependencyMacro)
+find_dependency(c1_lib_project REQUIRED)
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/include/c2_lib.h b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/include/c2_lib.h
new file mode 100644 (file)
index 0000000..5056814
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once
+
+void c2_hello();
diff --git a/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/src/c2_lib.cpp b/Tests/InstallMode/subpro_c_nested_lib/subsubpro_c2_lib/src/c2_lib.cpp
new file mode 100644 (file)
index 0000000..cd2c932
--- /dev/null
@@ -0,0 +1,12 @@
+#include <iostream>
+
+#include <c1_lib.h>
+#include <c2_lib.h>
+
+using namespace std;
+
+void c2_hello()
+{
+  cout << "Hello from c2_lib and also..." << endl;
+  c1_hello();
+}
diff --git a/Tests/InstallMode/subpro_d_executable/CMakeLists.txt b/Tests/InstallMode/subpro_d_executable/CMakeLists.txt
new file mode 100644 (file)
index 0000000..60189e2
--- /dev/null
@@ -0,0 +1,27 @@
+# This CMakeLists.txt is part of the subproject B (ExternalProject_Add).
+
+cmake_minimum_required(VERSION 3.20)
+project(subpro_d_executable LANGUAGES CXX)
+
+find_package(static_lib_project REQUIRED)
+find_package(shared_lib_project REQUIRED)
+find_package(c2_lib_project REQUIRED)
+
+add_executable(the_executable
+  "src/main.cpp"
+)
+
+target_link_libraries(the_executable PRIVATE
+  the_static_lib
+  the_shared_lib
+  the_c2_lib
+)
+
+# This is to fix an issue on AIX/GCC (see commit 4fc47424)
+set_property(TARGET the_executable PROPERTY NO_SYSTEM_FROM_IMPORTED 1)
+
+install(
+  TARGETS
+    the_executable
+  RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+)
diff --git a/Tests/InstallMode/subpro_d_executable/src/main.cpp b/Tests/InstallMode/subpro_d_executable/src/main.cpp
new file mode 100644 (file)
index 0000000..ec12004
--- /dev/null
@@ -0,0 +1,13 @@
+#include <cstdlib>
+
+#include <c2_lib.h>
+#include <shared_lib.h>
+#include <static_lib.h>
+
+int main()
+{
+  static_hello();
+  shared_hello();
+  c2_hello();
+  return EXIT_SUCCESS;
+}
diff --git a/Tests/InstallMode/superpro/CMakeLists.txt b/Tests/InstallMode/superpro/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ae4d25c
--- /dev/null
@@ -0,0 +1,29 @@
+# This CMakeLists.txt is part of the superproject (add_subdirectory).
+
+# Below file transfers are executed at configuration time!
+
+file(
+  COPY
+    "file_copy.txt"
+  DESTINATION
+    "${CMAKE_INSTALL_PREFIX}"
+)
+
+file(COPY_FILE
+  "${CMAKE_CURRENT_SOURCE_DIR}/file_copy_file.txt"
+  "${CMAKE_INSTALL_PREFIX}/file_copy_file.txt"
+)
+
+file(
+  INSTALL
+    "file_install.txt"
+  DESTINATION
+    "${CMAKE_INSTALL_PREFIX}"
+)
+
+file(
+  CREATE_LINK
+    "${CMAKE_CURRENT_SOURCE_DIR}/file_create_link_symbolic.txt"
+    "${CMAKE_INSTALL_PREFIX}/file_create_link_symbolic.txt"
+  SYMBOLIC
+)
diff --git a/Tests/InstallMode/superpro/file_copy.txt b/Tests/InstallMode/superpro/file_copy.txt
new file mode 100644 (file)
index 0000000..aacbb96
--- /dev/null
@@ -0,0 +1 @@
+This file should always be copied into CMAKE_INSTALL_PREFIX.
diff --git a/Tests/InstallMode/superpro/file_copy_file.txt b/Tests/InstallMode/superpro/file_copy_file.txt
new file mode 100644 (file)
index 0000000..aacbb96
--- /dev/null
@@ -0,0 +1 @@
+This file should always be copied into CMAKE_INSTALL_PREFIX.
diff --git a/Tests/InstallMode/superpro/file_create_link_symbolic.txt b/Tests/InstallMode/superpro/file_create_link_symbolic.txt
new file mode 100644 (file)
index 0000000..16a481b
--- /dev/null
@@ -0,0 +1,2 @@
+This file should always be installed into CMAKE_INSTALL_PREFIX
+as a symbolic link to the original file.
diff --git a/Tests/InstallMode/superpro/file_install.txt b/Tests/InstallMode/superpro/file_install.txt
new file mode 100644 (file)
index 0000000..eac9782
--- /dev/null
@@ -0,0 +1,6 @@
+This file should be placed in CMAKE_INSTALL_PREFIX
+as a copy if the CMAKE_INSTALL_MODE environment variable
+is unset or equals "COPY".
+If the variable's value is "SYMLINK" or "SYMLINK_OR_COPY",
+the CMAKE_INSTALL_PREFIX should rather receive a symbolic
+link to this file.
index 8664572..3b4fccc 100644 (file)
@@ -7,4 +7,8 @@ if(MSVC AND NOT MSVC_VERSION LESS 1400)
     -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake)
   add_executable(MSManifestNone main.c)
   set_property(TARGET MSManifestNone PROPERTY LINK_FLAGS "/MANIFEST:NO")
+elseif(WIN32 AND CMAKE_C_COMPILER_ID MATCHES "Clang")
+  add_test(NAME MSManifest.Single COMMAND
+    ${CMAKE_COMMAND} -Dexe=$<TARGET_FILE:MSManifest>
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake)
 endif()
index 19d8de7..0d960ad 100644 (file)
@@ -6,7 +6,7 @@ add_executable(MSMultipleManifest main.c
  ${CMAKE_CURRENT_BINARY_DIR}/test_manifest2.manifest
  ${CMAKE_CURRENT_BINARY_DIR}/test_manifest3.manifest)
 
-if(MSVC AND NOT MSVC_VERSION LESS 1400)
+if((MSVC AND NOT MSVC_VERSION LESS 1400) OR (WIN32 AND CMAKE_C_COMPILER_ID MATCHES "Clang") )
   add_test(NAME MSManifest.Multiple COMMAND
     ${CMAKE_COMMAND} -Dexe=$<TARGET_FILE:MSMultipleManifest>
     -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake)
diff --git a/Tests/Qt6Autogen/CMakeLists.txt b/Tests/Qt6Autogen/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a603b50
--- /dev/null
@@ -0,0 +1,8 @@
+# Set Qt test version and include the Autogen test macros
+set(QT_TEST_VERSION 6)
+include("../QtAutogen/TestMacros.cmake")
+
+# Common tests
+include("../QtAutogen/Tests.cmake")
+
+set(TEST_BUILD_DIRS "${TEST_BUILD_DIRS}" PARENT_SCOPE)
index 5803859..e62a6aa 100644 (file)
@@ -21,27 +21,27 @@ if (QT_TEST_VERSION EQUAL 4)
     qt4_generate_moc(${ARGN})
   endmacro()
 
-elseif(QT_TEST_VERSION EQUAL 5)
+elseif(QT_TEST_VERSION GREATER_EQUAL 5)
 
-  find_package(Qt5Core REQUIRED)
+  find_package(Qt${QT_TEST_VERSION}Core REQUIRED)
 
-  set(QT_QTCORE_TARGET Qt5::Core)
-  set(QT_LIBRARIES Qt5::Core)
+  set(QT_QTCORE_TARGET Qt${QT_TEST_VERSION}::Core)
+  set(QT_LIBRARIES Qt${QT_TEST_VERSION}::Core)
 
   # Include directories
-  include_directories(${Qt5Core_INCLUDE_DIRS})
+  include_directories(${Qt${QT_TEST_VERSION}Core_INCLUDE_DIRS})
 
   # Definitions
-  if(Qt5_POSITION_INDEPENDENT_CODE AND CMAKE_CXX_COMPILE_OPTIONS_PIC)
+  if(Qt${QT_TEST_VERSION}_POSITION_INDEPENDENT_CODE AND CMAKE_CXX_COMPILE_OPTIONS_PIC)
     add_definitions(${CMAKE_CXX_COMPILE_OPTIONS_PIC})
   endif()
 
   # Qt macros
   macro(qtx_wrap_cpp)
-    qt5_wrap_cpp(${ARGN})
+    cmake_language(CALL qt${QT_TEST_VERSION}_wrap_cpp ${ARGN})
   endmacro()
   macro(qtx_generate_moc)
-    qt5_generate_moc(${ARGN})
+    cmake_language(CALL qt${QT_TEST_VERSION}_generate_moc ${ARGN})
   endmacro()
 
 else()
index b76d341..e5eb751 100644 (file)
@@ -21,27 +21,27 @@ if (QT_TEST_VERSION EQUAL 4)
     qt4_generate_moc(${ARGN})
   endmacro()
 
-elseif(QT_TEST_VERSION EQUAL 5)
+elseif(QT_TEST_VERSION GREATER_EQUAL 5)
 
-  find_package(Qt5Widgets REQUIRED)
+  find_package(Qt${QT_TEST_VERSION}Widgets REQUIRED)
 
-  set(QT_QTCORE_TARGET Qt5::Core)
-  set(QT_LIBRARIES Qt5::Widgets)
+  set(QT_QTCORE_TARGET Qt${QT_TEST_VERSION}::Core)
+  set(QT_LIBRARIES Qt${QT_TEST_VERSION}::Widgets)
 
   # Include directories
-  include_directories(${Qt5Widgets_INCLUDE_DIRS})
+  include_directories(${Qt${QT_TEST_VERSION}Widgets_INCLUDE_DIRS})
 
   # Definitions
-  if(Qt5_POSITION_INDEPENDENT_CODE AND CMAKE_CXX_COMPILE_OPTIONS_PIC)
+  if(Qt${QT_TEST_VERSION}_POSITION_INDEPENDENT_CODE AND CMAKE_CXX_COMPILE_OPTIONS_PIC)
     add_definitions(${CMAKE_CXX_COMPILE_OPTIONS_PIC})
   endif()
 
   # Qt macros
   macro(qtx_wrap_cpp)
-    qt5_wrap_cpp(${ARGN})
+    cmake_language(CALL qt${QT_TEST_VERSION}_wrap_cpp ${ARGN})
   endmacro()
   macro(qtx_generate_moc)
-    qt5_generate_moc(${ARGN})
+    cmake_language(CALL qt${QT_TEST_VERSION}_generate_moc ${ARGN})
   endmacro()
 
 else()
index 17855ff..cac680f 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.11)
+cmake_minimum_required(VERSION 3.16)
 project(AutogenOriginDependsOff)
 include("../AutogenCoreTest.cmake")
 
index 5aabe0e..37ce90b 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(AutogenOriginDependsOn)
 include("../AutogenCoreTest.cmake")
 
index 492b5db..cf3f155 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(AutogenTargetDepends)
 include("../AutogenCoreTest.cmake")
 
index d9fdf5c..8a9a5d2 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(Complex)
 include("../AutogenGuiTest.cmake")
 
@@ -16,6 +16,8 @@ add_library(privateSlot OBJECT private_slot.cpp)
 # Pass Qt compiler features to targets that don't link against Qt
 target_compile_features(codeeditorLib PRIVATE ${QT_COMPILE_FEATURES})
 target_compile_features(privateSlot PRIVATE ${QT_COMPILE_FEATURES})
+target_link_libraries(codeeditorLib PRIVATE ${QT_LIBRARIES})
+target_link_libraries(privateSlot PRIVATE ${QT_LIBRARIES})
 
 configure_file(generated_resource.qrc.in generated_resource.qrc @ONLY)
 add_custom_command(
index 80d6a55..9c9dbc3 100644 (file)
@@ -70,7 +70,11 @@ int CodeEditor::lineNumberAreaWidth()
     ++digits;
   }
 
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
+  int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits;
+#else
   int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits;
+#endif
 
   return space;
 }
index e95c626..5c70e43 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.12)
+cmake_minimum_required(VERSION 3.16)
 project(GlobalAutogenTarget)
 include("../AutogenCoreTest.cmake")
 
@@ -74,6 +74,7 @@ execute_process(
         -T "${CMAKE_GENERATOR_TOOLSET}"
         "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
         "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+        "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
         "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
     WORKING_DIRECTORY "${GAT_BDIR}"
     OUTPUT_VARIABLE output
index 3925197..0e3df6f 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.12)
+cmake_minimum_required(VERSION 3.16)
 project(GAT)
 include("../../AutogenCoreTest.cmake")
 
@@ -9,7 +9,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 set(CMAKE_AUTOMOC ON)
 set(CMAKE_AUTOUIC ON)
 set(CMAKE_AUTORCC ON)
-# Disable ORIGN_DEPENDS and enable AUTOGEN global targets
+# Disable ORIGIN_DEPENDS and enable AUTOGEN global targets
 set(CMAKE_AUTOGEN_ORIGIN_DEPENDS OFF)
 set(CMAKE_GLOBAL_AUTOGEN_TARGET ON)
 set(CMAKE_GLOBAL_AUTORCC_TARGET ON)
index c08efc4..27c5f43 100644 (file)
@@ -1,21 +1,23 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(MacOsFW)
 include("../AutogenGuiTest.cmake")
 
-find_package(Qt5Test REQUIRED)
+find_package(Qt${QT_TEST_VERSION}Test REQUIRED)
+
+if(QT_TEST_VERSION EQUAL 5)
+  set(CMAKE_CXX_STANDARD 11)
+elseif(QT_TEST_VERSION EQUAL 6)
+  set(CMAKE_CXX_STANDARD 17)
+else()
+  message(FATAL_ERROR "Unsupported Qt version: ${QT_TEST_VERSION}")
+endif()
 
-set(CMAKE_CXX_STANDARD 11)
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/bin)
 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/lib)
 set(CMAKE_INSTALL_NAME_DIR ${CMAKE_BINARY_DIR}/output/lib)
 
-if(POLICY CMP0042) # in CMake 3.0.0+
-  set (CMAKE_MACOSX_RPATH OFF) # otherwise ON by default
-endif(POLICY CMP0042)
-
-if(POLICY CMP0068) # in CMake 3.9+
-  cmake_policy(SET CMP0068 NEW)
-endif(POLICY CMP0068)
+set (CMAKE_MACOSX_RPATH OFF) # otherwise ON by default
+cmake_policy(SET CMP0068 NEW)
 
 add_subdirectory(src)
 add_subdirectory(test)
index a02be00..67e2c8a 100644 (file)
@@ -9,7 +9,7 @@ set(MACOS_FW_LIB_HDRS
 include_directories(
   ${CMAKE_CURRENT_SOURCE_DIR}
   ${CMAKE_CURRENT_BINARY_DIR}
-  ${Qt5Core_INCLUDE_DIRS}
+  ${Qt${QT_TEST_VERSION}Core_INCLUDE_DIRS}
 )
 
 add_library(macos_fw_lib SHARED
@@ -28,6 +28,4 @@ set_target_properties(macos_fw_lib PROPERTIES
   POSITION_INDEPENDENT_CODE ON
   PUBLIC_HEADER "${MACOS_FW_LIB_HDRS}"
 )
-target_link_libraries(macos_fw_lib
-  Qt5::Core
-)
+target_link_libraries(macos_fw_lib PRIVATE ${QT_QTCORE_TARGET})
index 521c184..8cb1bc5 100644 (file)
@@ -4,16 +4,16 @@ include_directories(
   ${CMAKE_CURRENT_SOURCE_DIR}/../src
 )
 include_directories(SYSTEM
-  ${Qt5Core_INCLUDE_DIRS}
-  ${Qt5Widgets_INCLUDE_DIRS}
+  ${Qt${QT_TEST_VERSION}Core_INCLUDE_DIRS}
+  ${Qt${QT_TEST_VERSION}Widgets_INCLUDE_DIRS}
 )
 
 set(testname AutomocMacosFWLib)
 add_executable(${testname} testMacosFWLib.cpp)
 set_target_properties(${testname} PROPERTIES AUTOMOC TRUE)
-target_link_libraries(${testname}
-  Qt5::Core
-  Qt5::Widgets
-  Qt5::Test
+target_link_libraries(${testname} PRIVATE
+  Qt${QT_TEST_VERSION}::Core
+  Qt${QT_TEST_VERSION}::Widgets
+  Qt${QT_TEST_VERSION}::Test
   macos_fw_lib
 )
index df8a2a6..f9ac7db 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(ManySources)
 include("../AutogenGuiTest.cmake")
 
index 5c58a82..7ab3a8e 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(MocCMP0071)
 include("../AutogenCoreTest.cmake")
 
index 954fe3d..4375b17 100644 (file)
@@ -1,4 +1,3 @@
-cmake_minimum_required(VERSION 3.10)
 cmake_policy(SET CMP0071 NEW)
 
 # *Generate* files
index 68fa067..3771487 100644 (file)
@@ -1,4 +1,3 @@
-cmake_minimum_required(VERSION 3.10)
 cmake_policy(SET CMP0071 OLD)
 
 # *Generate* files
index 559cffe..b19dc6a 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(MocCMP0100)
 include("../AutogenCoreTest.cmake")
 
index 654b31e..aaaf7fb 100644 (file)
@@ -1,4 +1,3 @@
-cmake_minimum_required(VERSION 3.16)
 cmake_policy(SET CMP0100 NEW)
 
 add_executable(mocCMP0100New
index 2be0535..006cda1 100644 (file)
@@ -1,4 +1,3 @@
-cmake_minimum_required(VERSION 3.16)
 cmake_policy(SET CMP0100 OLD)
 
 # Generate moc files externally.
index 04c8baf..4224d2f 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.15)
+cmake_minimum_required(VERSION 3.16)
 project(MocInclude)
 get_filename_component(CS_REAL ${CMAKE_CURRENT_SOURCE_DIR} REALPATH)
 include("${CS_REAL}/../AutogenCoreTest.cmake")
index 8b11b46..c28616b 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.15)
+cmake_minimum_required(VERSION 3.16)
 project(MocIncludeSymlink)
 include("../AutogenCoreTest.cmake")
 
@@ -63,6 +63,7 @@ macro(buildMocInclude sourceDir binaryDir)
     CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
                 "-DCMAKE_AUTOMOC_PATH_PREFIX=ON"
                 "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+                "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
                 "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
     OUTPUT_VARIABLE output
   )
index bf13d18..d8dc4a3 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(MocMacroName)
 include("../AutogenCoreTest.cmake")
 
index f4fde58..b5d405a 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(MocOnly)
 include("../AutogenCoreTest.cmake")
 
index 19ee658..169e6cb 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(MocOptions)
 include("../AutogenCoreTest.cmake")
 
index b0125f6..db44da3 100644 (file)
@@ -1,10 +1,10 @@
-cmake_minimum_required(VERSION 3.11)
+cmake_minimum_required(VERSION 3.16)
 project(MocOsMacros)
 include("../AutogenCoreTest.cmake")
 
 # Tests if moc processes Q_OS_XXX macros
 
-message( "Qt5Core_VERSION: ${Qt5Core_VERSION}" )
+message( "Qt${QT_TEST_VERSION}Core_VERSION: ${Qt${QT_TEST_VERSION}Core_VERSION}" )
 message(
   "CMAKE_CXX_COMPILER_PREDEFINES_COMMAND: "
   ${CMAKE_CXX_COMPILER_PREDEFINES_COMMAND} )
@@ -12,7 +12,7 @@ message(
 # On some platforms (e.g. MAC) Q_OS_XXX requires moc to include moc_predefs.h
 # which is supported since Qt 5.8 and requires
 # CMAKE_CXX_COMPILER_PREDEFINES_COMMAND to be defined.
-if( ( ${Qt5Core_VERSION} VERSION_GREATER_EQUAL "5.8" ) AND
+if( ( ${Qt${QT_TEST_VERSION}Core_VERSION} VERSION_GREATER_EQUAL "5.8" ) AND
   DEFINED CMAKE_CXX_COMPILER_PREDEFINES_COMMAND
 )
   message( "Test enabled!" )
index c886736..b9e20c8 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(MocSkipSource)
 include("../AutogenCoreTest.cmake")
 
index e8af6c9..88d0998 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(ObjectLibrary)
 include("../AutogenCoreTest.cmake")
 
@@ -11,7 +11,7 @@ add_subdirectory(a)
 # Object library b defined locally
 include_directories(b)
 add_library(b OBJECT b/classb.cpp)
-target_compile_features(b PRIVATE ${QT_COMPILE_FEATURES})
+target_link_libraries(b PRIVATE ${QT_LIBRARIES})
 
 # Executable with OBJECT library generator expressions
 add_executable(someProgram main.cpp $<TARGET_OBJECTS:a> $<TARGET_OBJECTS:b>)
index fe76ac3..5ace3ae 100644 (file)
@@ -1,2 +1,2 @@
 add_library(a OBJECT classa.cpp)
-target_compile_features(a PRIVATE ${QT_COMPILE_FEATURES})
+target_link_libraries(a PRIVATE ${QT_LIBRARIES})
index 299bcbf..29628eb 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(Parallel)
 include("../AutogenGuiTest.cmake")
 
index 5c7d547..d94aba5 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(Parallel1)
 include("../AutogenGuiTest.cmake")
 
index 668aea4..58667a8 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(Parallel2)
 include("../AutogenGuiTest.cmake")
 
index 5c50f5e..cc3aae0 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(Parallel3)
 include("../AutogenGuiTest.cmake")
 
index 2c40c6a..2b81e98 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(Parallel4)
 include("../AutogenGuiTest.cmake")
 
index cddece3..5543b9a 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(ParallelAUTO)
 include("../AutogenGuiTest.cmake")
 
index a8e2af1..c8f9d17 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(RccEmpty)
 include("../AutogenCoreTest.cmake")
 
index 61b9601..b44973d 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(RccOffMocLibrary)
 include("../AutogenCoreTest.cmake")
 
@@ -9,9 +9,7 @@ include("../AutogenCoreTest.cmake")
 add_library(empty STATIC empty.cpp not_generated_file.qrc)
 set_target_properties(empty PROPERTIES AUTORCC OFF)
 set_target_properties(empty PROPERTIES AUTOMOC TRUE)
-target_link_libraries(empty no_link_language)
+target_link_libraries(empty PRIVATE no_link_language ${QT_LIBRARIES})
 add_library(no_link_language STATIC empty.h)
 set_target_properties(no_link_language PROPERTIES AUTOMOC TRUE)
-# Pass Qt compiler features to targets that don't link against Qt
-target_compile_features(no_link_language PRIVATE ${QT_COMPILE_FEATURES})
-target_compile_features(empty PRIVATE ${QT_COMPILE_FEATURES})
+target_link_libraries(no_link_language PRIVATE ${QT_LIBRARIES})
index f3776f5..f3271e0 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(RccOnly)
 include("../AutogenCoreTest.cmake")
 
index 4223274..a79177f 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(RccSkipSource)
 include("../AutogenCoreTest.cmake")
 
index c53e857..76dbdf5 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(RerunMocBasic)
 include("../AutogenCoreTest.cmake")
 
@@ -63,6 +63,7 @@ execute_process(
           ${_D_CMAKE_GENERATOR_INSTANCE}
           "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
           "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+          "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
           "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
   RESULT_VARIABLE exit_code
   OUTPUT_VARIABLE output
index 42f2f57..e27a824 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(MocBasic)
 include("../../AutogenCoreTest.cmake")
 
index 2677659..3a9244d 100644 (file)
@@ -1,6 +1,6 @@
 # This test checks whether adding a source file to the project triggers an AUTOMOC re-run.
 
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(RerunMocOnAddFile)
 include("../AutogenCoreTest.cmake")
 
@@ -64,6 +64,7 @@ try_compile(MOC_RERUN
   MocOnAddFile
   CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
               "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+              "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
               "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
   OUTPUT_VARIABLE output
 )
index 9e5e21c..e600137 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(MocOnAddFile)
 include("@CMAKE_CURRENT_LIST_DIR@/../AutogenCoreTest.cmake")
 
index c5811eb..b17e4c5 100644 (file)
@@ -1,6 +1,6 @@
 # This test checks whether a missing dependency of the moc output triggers an AUTOMOC re-run.
 
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(RerunMocOnMissingDependency)
 include("../AutogenCoreTest.cmake")
 
@@ -13,10 +13,10 @@ add_executable(exe "${main_source}")
 set(testProjectTemplateDir "${CMAKE_CURRENT_SOURCE_DIR}/MocOnMissingDependency")
 set(testProjectSrc "${CMAKE_CURRENT_BINARY_DIR}/MocOnMissingDependency")
 set(testProjectBinDir "${CMAKE_CURRENT_BINARY_DIR}/MocOnMissingDependency-build")
-if(DEFINED Qt5Core_VERSION AND Qt5Core_VERSION VERSION_GREATER_EQUAL "5.15.0")
-    set(moc_depfiles_supported TRUE)
+if(DEFINED Qt${QT_TEST_VERSION}Core_VERSION AND Qt${QT_TEST_VERSION}Core_VERSION VERSION_GREATER_EQUAL "5.15.0")
+  set(moc_depfiles_supported TRUE)
 else()
-    set(moc_depfiles_supported FALSE)
+  set(moc_depfiles_supported FALSE)
 endif()
 
 # Utility macros
@@ -48,6 +48,7 @@ try_compile(MOC_RERUN
   MocOnMissingDependency
   CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
               "-DCMAKE_AUTOGEN_VERBOSE=ON"
+              "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
               "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
   OUTPUT_VARIABLE output
 )
index a7fb2d7..2d2edb4 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(RerunMocPlugin)
 include("../AutogenCoreTest.cmake")
 
@@ -63,6 +63,7 @@ try_compile(MOC_PLUGIN
   MocPlugin
   CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
               "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+              "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
               "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
   OUTPUT_VARIABLE output
 )
index 5068289..8097fd0 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(MocPlugin)
 include("../../AutogenGuiTest.cmake")
 
@@ -22,7 +22,7 @@ configure_file(jsonIn/StyleE.json jsonFiles/StyleE_Custom.json)
 set(CMAKE_AUTOMOC TRUE)
 
 include_directories("${CMAKE_CURRENT_BINARY_DIR}/jsonFiles")
-link_libraries(Qt5::Widgets)
+link_libraries(Qt${QT_TEST_VERSION}::Widgets)
 
 add_library(PlugA STATIC StyleA.cpp)
 add_library(PlugB STATIC StyleB.cpp)
index 33c01ac..1598bfd 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.11.2)
+cmake_minimum_required(VERSION 3.16)
 project(RerunRccConfigChange)
 include("../AutogenCoreTest.cmake")
 
@@ -33,6 +33,7 @@ try_compile(RCC_DEPENDS
   RccConfigChange
   CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
               "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+              "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
               "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
   OUTPUT_VARIABLE output
 )
index e2dd0ac..83f3a45 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.11.2)
+cmake_minimum_required(VERSION 3.16)
 project(RccConfigChange)
 include("../../AutogenCoreTest.cmake")
 
index 1301550..15e38db 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(RerunRccDepends)
 include("../AutogenCoreTest.cmake")
 
@@ -66,6 +66,7 @@ try_compile(RCC_DEPENDS
   RccDepends
   CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
               "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+              "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
               "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
   OUTPUT_VARIABLE output
 )
index 150f849..6bba163 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(RccDepends)
 include("../../AutogenCoreTest.cmake")
 
index 9b114e9..979e878 100644 (file)
@@ -66,6 +66,7 @@ execute_process(
           "${build_type_extra}"
           "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
           "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+          "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
           "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
   RESULT_VARIABLE exit_code
   OUTPUT_VARIABLE output
index c787db1..1775725 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 
 project(UicOnFileChange)
 include("@CMAKE_CURRENT_LIST_DIR@/../AutogenGuiTest.cmake")
index f3536ba..25ea822 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(StaticLibraryCycle)
 include("../AutogenCoreTest.cmake")
 
index 9dcf31f..529592e 100644 (file)
@@ -7,8 +7,17 @@ else()
 endif()
 list(APPEND Autogen_BUILD_OPTIONS
     "-DCMAKE_AUTOGEN_VERBOSE=1"
-    "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
 )
+if(Qt${QT_TEST_VERSION}Core_DIR)
+  get_filename_component(prefix "${Qt${QT_TEST_VERSION}Core_DIR}" DIRECTORY)
+  get_filename_component(prefix "${prefix}" DIRECTORY)
+  get_filename_component(prefix "${prefix}" DIRECTORY)
+  list(APPEND Autogen_BUILD_OPTIONS "-DCMAKE_PREFIX_PATH:STRING=${prefix}")
+else()
+  list(APPEND Autogen_BUILD_OPTIONS
+    "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+  )
+endif()
 # XXX(xcode-per-cfg-src): Drop the NO_PER_CONFIG_SOURCES exclusion
 # when the Xcode generator supports per-config sources.
 if(CMAKE_GENERATOR STREQUAL "Xcode")
index 929868b..042d18f 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(UicInclude)
 include("../AutogenGuiTest.cmake")
 
index e022764..167ae49 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(UicInterface)
 include("../AutogenGuiTest.cmake")
 
@@ -11,12 +11,12 @@ set(CMAKE_AUTOUIC ON)
 set(CMAKE_VERBOSE_MAKEFILE ON)
 
 add_library(KI18n klocalizedstring.cpp)
-target_link_libraries(KI18n ${QT_QTCORE_TARGET})
+target_link_libraries(KI18n PRIVATE ${QT_QTCORE_TARGET})
 
 set(autouic_options
   -tr tr2$<$<NOT:$<BOOL:$<TARGET_PROPERTY:NO_KUIT_SEMANTIC>>>:x>i18n
 )
-if (NOT Qt5Widgets_VERSION VERSION_LESS 5.3.0)
+if (NOT Qt${QT_TEST_VERSION}Widgets_VERSION VERSION_LESS 5.3.0)
   list(APPEND autouic_options -include klocalizedstring.h)
 endif()
 
index 076299d..b938a17 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.13)
+cmake_minimum_required(VERSION 3.16)
 project(UicNoGui)
 include("../AutogenCoreTest.cmake")
 
index b163254..e25b44d 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(UicOnly)
 include("../AutogenGuiTest.cmake")
 
index dc3b7d4..15dfe65 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16)
 project(UicSkipSource)
 include("../AutogenGuiTest.cmake")
 
index 8fa6041..6d26f99 100644 (file)
@@ -1,6 +1,6 @@
 enable_language(CXX)
 
-find_package(Qt5 REQUIRED COMPONENTS Core)
+find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core)
 
 # Detect `-NOTFOUND` libraries at generate time.
 cmake_policy(SET CMP0111 NEW)
index 9a66cde..2632ffa 100644 (file)
@@ -1,3 +1,3 @@
-cmake_minimum_required(VERSION 3.13)
+cmake_minimum_required(VERSION 3.16)
 project(${RunCMake_TEST} NONE)
 include(${RunCMake_TEST}.cmake)
index a44bc5a..6c42cc2 100644 (file)
@@ -1,9 +1,9 @@
 enable_language(CXX)
 
 function (use_autogen target)
-  find_package(Qt5 REQUIRED COMPONENTS Core Widgets)
-  set(Qt5Core_VERSION_MAJOR "${Qt5Core_VERSION_MAJOR}" PARENT_SCOPE)
-  set(Qt5Core_VERSION_MINOR "${Qt5Core_VERSION_MINOR}" PARENT_SCOPE)
+  find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core Widgets)
+  set(Qt${with_qt_version}Core_VERSION_MAJOR "${Qt${with_qt_version}Core_VERSION_MAJOR}" PARENT_SCOPE)
+  set(Qt${with_qt_version}Core_VERSION_MINOR "${Qt${with_qt_version}Core_VERSION_MINOR}" PARENT_SCOPE)
   set_property(TARGET "${target}" PROPERTY AUTOMOC 1)
   set_property(TARGET "${target}" PROPERTY AUTORCC 1)
   set_property(TARGET "${target}" PROPERTY AUTOUIC 1)
index 5421ba0..2e7b8ad 100644 (file)
@@ -1,9 +1,9 @@
 enable_language(CXX)
 
 function (use_autogen target)
-  find_package(Qt5 REQUIRED COMPONENTS Core Widgets)
-  set(Qt5Core_VERSION_MAJOR "${Qt5Core_VERSION_MAJOR}" PARENT_SCOPE)
-  set(Qt5Core_VERSION_MINOR "${Qt5Core_VERSION_MINOR}" PARENT_SCOPE)
+  find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core Widgets)
+  set(Qt${with_qt_version}Core_VERSION_MAJOR "${Qt${with_qt_version}Core_VERSION_MAJOR}" PARENT_SCOPE)
+  set(Qt${with_qt_version}Core_VERSION_MINOR "${Qt${with_qt_version}Core_VERSION_MINOR}" PARENT_SCOPE)
   set_property(TARGET "${target}" PROPERTY AUTOMOC 1)
   set_property(TARGET "${target}" PROPERTY AUTORCC 1)
   set_property(TARGET "${target}" PROPERTY AUTOUIC 1)
index 35f1cd1..d9296c4 100644 (file)
@@ -1,13 +1,13 @@
 enable_language(CXX)
 
 function (use_autogen target)
-  find_package(Qt5 REQUIRED COMPONENTS Core Widgets)
+  find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core Widgets)
   set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
     PROPERTY
-      Qt5Core_VERSION_MAJOR "${Qt5Core_VERSION_MAJOR}")
+      Qt${with_qt_version}Core_VERSION_MAJOR "${Qt${with_qt_version}Core_VERSION_MAJOR}")
   set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
     PROPERTY
-      Qt5Core_VERSION_MINOR "${Qt5Core_VERSION_MINOR}")
+      Qt${with_qt_version}Core_VERSION_MINOR "${Qt${with_qt_version}Core_VERSION_MINOR}")
   set_property(TARGET "${target}" PROPERTY AUTOMOC 1)
   set_property(TARGET "${target}" PROPERTY AUTORCC 1)
   set_property(TARGET "${target}" PROPERTY AUTOUIC 1)
index bbcbd5e..e4c5811 100644 (file)
@@ -1,7 +1,13 @@
 include(RunCMake)
 
 run_cmake(NoQt)
-if (with_qt5)
+if (DEFINED with_qt_version)
+  set(RunCMake_TEST_OPTIONS
+    -Dwith_qt_version=${with_qt_version}
+    "-DQt${with_qt_version}_DIR:PATH=${Qt${with_qt_version}_DIR}"
+    "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
+  )
+
   run_cmake(QtInFunction)
   run_cmake(QtInFunctionNested)
   run_cmake(QtInFunctionProperty)
diff --git a/Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/CMakeLists.txt b/Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bbc08e6
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.21)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/CheckEnvironmentVar-build-stdout.txt b/Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/CheckEnvironmentVar-build-stdout.txt
new file mode 100644 (file)
index 0000000..f0f2efc
--- /dev/null
@@ -0,0 +1 @@
+This message is printed by echo_message.bat
diff --git a/Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/CheckEnvironmentVar.cmake b/Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/CheckEnvironmentVar.cmake
new file mode 100644 (file)
index 0000000..63d6068
--- /dev/null
@@ -0,0 +1,2 @@
+set(CMAKE_MSVCIDE_RUN_PATH "${CMAKE_SOURCE_DIR}")
+add_custom_target(main COMMAND echo_message)
diff --git a/Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/RunCMakeTest.cmake b/Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..a424ff2
--- /dev/null
@@ -0,0 +1,8 @@
+include(RunCMake)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CheckEnvironmentVar-build)
+run_cmake(CheckEnvironmentVar)
+set(RunCMake_TEST_NO_CLEAN 1)
+run_cmake_command(CheckEnvironmentVar-build ${CMAKE_COMMAND} --build . --config Debug --target main)
+unset(RunCMake_TEST_BINARY_DIR)
+unset(RunCMake_TEST_NO_CLEAN)
diff --git a/Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/echo_message.bat b/Tests/RunCMake/CMAKE_MSVCIDE_RUN_PATH/echo_message.bat
new file mode 100755 (executable)
index 0000000..92c6017
--- /dev/null
@@ -0,0 +1 @@
+echo This message is printed by echo_message.bat\r
diff --git a/Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-NEW.cmake b/Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-NEW.cmake
new file mode 100644 (file)
index 0000000..5a2b018
--- /dev/null
@@ -0,0 +1,9 @@
+include(CMakeDependentOption)
+
+cmake_policy(SET CMP0127 NEW)
+
+set(A 1)
+set(B 1)
+set(C 0)
+cmake_dependent_option(USE_FOO "Use Foo" ON "A AND (B OR C)" OFF)
+message(STATUS "USE_FOO='${USE_FOO}'")
diff --git a/Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-WARN-stderr.txt b/Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-WARN-stderr.txt
new file mode 100644 (file)
index 0000000..b16e84b
--- /dev/null
@@ -0,0 +1,9 @@
+^CMake Warning \(dev\) at [^
+]*/Modules/CMakeDependentOption.cmake:[0-9]+ \(message\):
+  Policy CMP0127 is not set: cmake_dependent_option\(\) supports full Condition
+  Syntax.  Run "cmake --help-policy CMP0127" for policy details.  Use the
+  cmake_policy command to set the policy and suppress this warning.
+Call Stack \(most recent call first\):
+  [^
+]*/Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-WARN.cmake:[0-9]+ \(cmake_dependent_option\)
+This warning is for project developers.  Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-WARN-stdout.txt b/Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-WARN-stdout.txt
new file mode 100644 (file)
index 0000000..d89dbd3
--- /dev/null
@@ -0,0 +1,2 @@
+-- USE_FOO='OFF'
+-- USE_BAR='ON'
diff --git a/Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-WARN.cmake b/Tests/RunCMake/CMakeDependentOption/Parentheses-CMP0127-WARN.cmake
new file mode 100644 (file)
index 0000000..00d440d
--- /dev/null
@@ -0,0 +1,9 @@
+include(CMakeDependentOption)
+
+set(A 1)
+set(B 1)
+set(C 0)
+cmake_dependent_option(USE_FOO "Use Foo" ON "A AND (B OR C)" OFF)
+message(STATUS "USE_FOO='${USE_FOO}'")
+cmake_dependent_option(USE_BAR "Use Bar" ON "A;B" OFF)
+message(STATUS "USE_BAR='${USE_BAR}'")
diff --git a/Tests/RunCMake/CMakeDependentOption/Regex-CMP0127-NEW-stdout.txt b/Tests/RunCMake/CMakeDependentOption/Regex-CMP0127-NEW-stdout.txt
new file mode 100644 (file)
index 0000000..15b56a1
--- /dev/null
@@ -0,0 +1 @@
+-- USE_FOO='ON'
diff --git a/Tests/RunCMake/CMakeDependentOption/Regex-CMP0127-NEW.cmake b/Tests/RunCMake/CMakeDependentOption/Regex-CMP0127-NEW.cmake
new file mode 100644 (file)
index 0000000..e92c1e6
--- /dev/null
@@ -0,0 +1,7 @@
+include(CMakeDependentOption)
+
+cmake_policy(SET CMP0127 NEW)
+
+set(FOO "lower")
+cmake_dependent_option(USE_FOO "Use Foo" ON "FOO MATCHES \"(UPPER|lower)\"" OFF)
+message(STATUS "USE_FOO='${USE_FOO}'")
diff --git a/Tests/RunCMake/CMakeDependentOption/Regex-CMP0127-OLD-stdout.txt b/Tests/RunCMake/CMakeDependentOption/Regex-CMP0127-OLD-stdout.txt
new file mode 100644 (file)
index 0000000..15b56a1
--- /dev/null
@@ -0,0 +1 @@
+-- USE_FOO='ON'
@@ -1,5 +1,7 @@
 include(CMakeDependentOption)
 
+cmake_policy(SET CMP0127 OLD)
+
 set(FOO "lower")
 cmake_dependent_option(USE_FOO "Use Foo" ON "FOO MATCHES (UPPER|lower)" OFF)
 message(STATUS "USE_FOO='${USE_FOO}'")
index e1045f2..61e046f 100644 (file)
@@ -1,3 +1,6 @@
 include(RunCMake)
 
-run_cmake_script(Regex)
+run_cmake_script(Regex-CMP0127-NEW)
+run_cmake_script(Regex-CMP0127-OLD)
+run_cmake_script(Parentheses-CMP0127-NEW)
+run_cmake_script(Parentheses-CMP0127-WARN)
diff --git a/Tests/RunCMake/CMakeDependentOption/Simple-CMP0127-OLD-stdout.txt b/Tests/RunCMake/CMakeDependentOption/Simple-CMP0127-OLD-stdout.txt
new file mode 100644 (file)
index 0000000..15b56a1
--- /dev/null
@@ -0,0 +1 @@
+-- USE_FOO='ON'
diff --git a/Tests/RunCMake/CMakeDependentOption/Simple-CMP0127-OLD.cmake b/Tests/RunCMake/CMakeDependentOption/Simple-CMP0127-OLD.cmake
new file mode 100644 (file)
index 0000000..6db2128
--- /dev/null
@@ -0,0 +1,6 @@
+include(CMakeDependentOption)
+
+set(A1 1)
+set(bb 1)
+cmake_dependent_option(USE_FOO "Use Foo" ON "A1;bb" OFF)
+message(STATUS "USE_FOO='${USE_FOO}'")
index 86cb849..e24ef58 100644 (file)
@@ -151,8 +151,23 @@ endif()
 if(CMAKE_GENERATOR MATCHES "Make")
   add_RunCMake_test(Make -DMAKE_IS_GNU=${MAKE_IS_GNU})
 endif()
-if(CMake_TEST_Qt5)
+unset(ninja_test_with_qt_version)
+unset(ninja_qt_args)
+if(CMake_TEST_Qt6)
+  find_package(Qt6Widgets QUIET NO_MODULE)
+  if(Qt6Widgets_FOUND)
+    set(ninja_test_with_qt_version 6)
+    # Work around Qt6 not finding sibling dependencies without CMAKE_PREFIX_PATH
+    cmake_path(GET Qt6_DIR  PARENT_PATH base_dir)  # <base>/lib/cmake
+    cmake_path(GET base_dir PARENT_PATH base_dir)  # <base>/lib
+    cmake_path(GET base_dir PARENT_PATH base_dir)  # <base>
+    set(ninja_qt_args -DCMAKE_PREFIX_PATH=${base_dir})
+  endif()
+elseif(CMake_TEST_Qt5)
   find_package(Qt5Widgets QUIET NO_MODULE)
+  if(Qt5Widgets_FOUND)
+    set(ninja_test_with_qt_version 5)
+  endif()
 endif()
 if(CMAKE_GENERATOR MATCHES "Ninja")
   set(Ninja_ARGS
@@ -162,18 +177,27 @@ if(CMAKE_GENERATOR MATCHES "Ninja")
   if(CMAKE_Fortran_COMPILER)
     list(APPEND Ninja_ARGS -DTEST_Fortran=1)
   endif()
-  if(CMake_TEST_Qt5 AND Qt5Core_FOUND)
-    list(APPEND Ninja_ARGS -DCMake_TEST_Qt5=1 -DQt5Core_DIR=${Qt5Core_DIR} -DCMAKE_TEST_Qt5Core_Version=${Qt5Core_VERSION})
-    if(Qt5Widgets_FOUND)
-      list(APPEND Ninja_ARGS -DQt5Widgets_DIR=${Qt5Widgets_DIR})
-    endif()
+  if(ninja_test_with_qt_version)
+    list(APPEND Ninja_ARGS
+      -DCMake_TEST_Qt_version=${ninja_test_with_qt_version}
+      -DQt${ninja_test_with_qt_version}_DIR=${Qt${ninja_test_with_qt_version}_DIR}
+      -DQt${ninja_test_with_qt_version}Core_DIR=${Qt${ninja_test_with_qt_version}Core_DIR}
+      -DCMake_TEST_Qt${ninja_test_with_qt_version}Core_Version=${Qt${ninja_test_with_qt_version}Core_VERSION}
+      -DQt${ninja_test_with_qt_version}Widgets_DIR=${Qt${ninja_test_with_qt_version}Widgets_DIR}
+      ${ninja_qt_args}
+    )
   endif()
   add_RunCMake_test(Ninja)
   set(NinjaMultiConfig_ARGS
     -DCYGWIN=${CYGWIN} -DMSYS=${MSYS}
     )
-  if(CMake_TEST_Qt5 AND Qt5Core_FOUND)
-    list(APPEND NinjaMultiConfig_ARGS -DCMake_TEST_Qt5=1 -DQt5Core_DIR=${Qt5Core_DIR} -DCMAKE_TEST_Qt5Core_Version=${Qt5Core_VERSION})
+  if(ninja_test_with_qt_version)
+    list(APPEND NinjaMultiConfig_ARGS
+      -DCMake_TEST_Qt_version=${ninja_test_with_qt_version}
+      -DQt${ninja_test_with_qt_version}Core_DIR=${Qt${ninja_test_with_qt_version}Core_DIR}
+      -DCMake_TEST_Qt${ninja_test_with_qt_version}Core_Version=${Qt${ninja_test_with_qt_version}Core_VERSION}
+      ${ninja_qt_args}
+    )
   endif()
   if(DEFINED CMake_TEST_CUDA)
     list(APPEND NinjaMultiConfig_ARGS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
@@ -205,11 +229,29 @@ add_RunCMake_test(AndroidTestUtilities)
 if(CMake_TEST_APPLE_SILICON)
   add_RunCMake_test(AppleSilicon)
 endif()
-set(autogen_with_qt5 FALSE)
+set(want_NoQt_test TRUE)
+if(CMake_TEST_Qt6 AND Qt6Widgets_FOUND)
+  # Work around Qt6 not finding sibling dependencies without CMAKE_PREFIX_PATH
+  cmake_path(GET Qt6_DIR  PARENT_PATH base_dir)  # <base>/lib/cmake
+  cmake_path(GET base_dir PARENT_PATH base_dir)  # <base>/lib
+  cmake_path(GET base_dir PARENT_PATH base_dir)  # <base>
+  add_RunCMake_test(AutogenQt6 TEST_DIR Autogen
+    -Dwith_qt_version=6
+    "-DQt6_DIR:PATH=${Qt6_DIR}"
+    "-DCMAKE_PREFIX_PATH:STRING=${base_dir}"
+  )
+  set(want_NoQt_test FALSE)
+endif ()
 if(CMake_TEST_Qt5 AND Qt5Widgets_FOUND)
-  set(autogen_with_qt5 TRUE)
+  add_RunCMake_test(AutogenQt5 TEST_DIR Autogen
+    -Dwith_qt_version=5
+    "-DQt5_DIR:PATH=${Qt5_DIR}"
+  )
+  set(want_NoQt_test FALSE)
 endif ()
-add_RunCMake_test(Autogen -Dwith_qt5=${autogen_with_qt5})
+if(want_NoQt_test)
+  add_RunCMake_test(AutogenNoQt TEST_DIR Autogen)
+endif()
 
 add_RunCMake_test(ArtifactOutputDirs)
 
@@ -310,7 +352,7 @@ add_RunCMake_test(TargetProperties)
 add_RunCMake_test(ToolchainFile)
 add_RunCMake_test(find_dependency)
 add_RunCMake_test(CompileDefinitions)
-add_RunCMake_test(CompileFeatures)
+add_RunCMake_test(CompileFeatures -DCMake_NO_C_STANDARD=${CMake_NO_C_STANDARD} -DCMake_NO_CXX_STANDARD=${CMake_NO_CXX_STANDARD})
 add_RunCMake_test(Policy)
 add_RunCMake_test(PolicyScope)
 add_RunCMake_test(WriteBasicConfigVersionFile)
@@ -349,6 +391,7 @@ if(NOT CMake_TEST_EXTERNAL_CMAKE)
 endif()
 add_RunCMake_test(execute_process)
 add_RunCMake_test(export)
+add_RunCMake_test(cmake_host_system_information)
 add_RunCMake_test(cmake_language)
 add_RunCMake_test(cmake_minimum_required)
 add_RunCMake_test(cmake_parse_arguments)
@@ -374,12 +417,11 @@ add_RunCMake_test(ctest_disabled_test)
 add_RunCMake_test(ctest_skipped_test)
 add_RunCMake_test(ctest_update)
 add_RunCMake_test(ctest_upload)
+add_RunCMake_test(ctest_environment)
 add_RunCMake_test(ctest_fixtures)
-add_RunCMake_test(file -DMSYS=${MSYS})
+add_RunCMake_test(file -DCYGWIN=${CYGWIN} -DMSYS=${MSYS})
 add_RunCMake_test(file-CHMOD -DMSYS=${MSYS})
-if(HAVE_ELF_H OR CMAKE_SYSTEM_NAME STREQUAL "AIX")
-  add_RunCMake_test(file-RPATH -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DHAVE_ELF_H=${HAVE_ELF_H})
-endif()
+add_RunCMake_test(file-RPATH -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})
 add_RunCMake_test(find_file)
 add_RunCMake_test(find_library -DCYGWIN=${CYGWIN} -DMSYS=${MSYS})
 add_RunCMake_test(find_package -DMSYS=${MSYS})
@@ -557,6 +599,7 @@ if(CMake_TEST_FindGTK2)
 endif()
 
 if("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
+  add_RunCMake_test(CMAKE_MSVCIDE_RUN_PATH)
   add_RunCMake_test(include_external_msproject -DVS_PLATFORM_NAME=${CMAKE_VS_PLATFORM_NAME})
   if("${CMAKE_GENERATOR}" MATCHES "Visual Studio (9|10)" AND NOT CMAKE_VS_DEVENV_COMMAND)
     set(NO_USE_FOLDERS 1)
index 746ff8b..7997c78 100644 (file)
@@ -7,6 +7,7 @@ include("${RunCMake_SOURCE_DIR}/CPackTestHelpers.cmake")
 run_cpack_test(CUSTOM_BINARY_SPEC_FILE "RPM.CUSTOM_BINARY_SPEC_FILE" false "MONOLITHIC;COMPONENT")
 run_cpack_test(CUSTOM_NAMES "RPM.CUSTOM_NAMES;DEB.CUSTOM_NAMES;TGZ;DragNDrop" true "COMPONENT")
 run_cpack_test(DEBUGINFO "RPM.DEBUGINFO;DEB.DEBUGINFO" true "COMPONENT")
+run_cpack_test(DEBUGINFO "DEB.DEBUGINFO" true "MONOLITHIC")
 run_cpack_test_subtests(DEFAULT_PERMISSIONS "CMAKE_var_set;CPACK_var_set;both_set;invalid_CMAKE_var;invalid_CPACK_var" "RPM.DEFAULT_PERMISSIONS;DEB.DEFAULT_PERMISSIONS" false "MONOLITHIC;COMPONENT")
 run_cpack_test(DEPENDENCIES "RPM.DEPENDENCIES;DEB.DEPENDENCIES" true "COMPONENT")
 run_cpack_test(DIST "RPM.DIST" false "MONOLITHIC")
index cf4aa51..b3e6485 100644 (file)
@@ -1,8 +1,5 @@
 set(whitespaces_ "[\t\n\r ]*")
 
-set(EXPECTED_FILES_COUNT "6")
-set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
-
 if(GENERATOR_TYPE STREQUAL "RPM")
   set(NAME "Debuginfo")
   set(DEBUG_SUFFIX "debuginfo")
@@ -15,30 +12,49 @@ elseif(GENERATOR_TYPE STREQUAL "DEB")
   set(DEBUG_PKG "ddeb")
 endif()
 
-set(EXPECTED_FILE_1_NAME "${NAME}")
-set(EXPECTED_FILE_1_COMPONENT "applications")
-set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/test_prog")
+set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
 
-set(EXPECTED_FILE_2 "TestDinfo-pkg*-headers.${PKG}")
-set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+  set(EXPECTED_FILES_COUNT "6")
 
-set(EXPECTED_FILE_3 "TestDinfo-pkg*-libs.${PKG}")
-set(EXPECTED_FILE_CONTENT_3_LIST "/bas;/bas/libtest_lib.so")
+  set(EXPECTED_FILE_1_NAME "${NAME}")
+  set(EXPECTED_FILE_1_COMPONENT "applications")
+  set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/test_prog")
 
-set(EXPECTED_FILE_4 "${NAME}-applications-${DEBUG_SUFFIX}*.${DEBUG_PKG}")
-if(GENERATOR_TYPE STREQUAL "RPM")
-  set(EXPECTED_FILE_CONTENT_4 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp.*\.debug.*")
-elseif(GENERATOR_TYPE STREQUAL "DEB")
-  set(EXPECTED_FILE_CONTENT_4 ".*/usr/lib/debug/.build-id/.*\.debug.*")
-endif()
+  set(EXPECTED_FILE_2 "TestDinfo-pkg*-headers.${PKG}")
+  set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
 
-if(GENERATOR_TYPE STREQUAL "RPM")
-  set(EXPECTED_FILE_5 "libs-DebugInfoPackage.rpm")
-  set(EXPECTED_FILE_CONTENT_5 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/test_lib.cpp.*\.debug.*")
-elseif(GENERATOR_TYPE STREQUAL "DEB")
-  set(EXPECTED_FILE_5 "TestDinfo-pkg-libs-dbgsym.ddeb")
-  set(EXPECTED_FILE_CONTENT_5 ".*/usr/lib/debug/.build-id/.*\.debug.*")
-endif()
+  set(EXPECTED_FILE_3 "TestDinfo-pkg*-libs.${PKG}")
+  set(EXPECTED_FILE_CONTENT_3_LIST "/bas;/bas/libtest_lib.so")
+
+  set(EXPECTED_FILE_4 "${NAME}-applications-${DEBUG_SUFFIX}*.${DEBUG_PKG}")
+  if(GENERATOR_TYPE STREQUAL "RPM")
+    set(EXPECTED_FILE_CONTENT_4 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp.*\.debug.*")
+  elseif(GENERATOR_TYPE STREQUAL "DEB")
+    set(EXPECTED_FILE_CONTENT_4 ".*/usr/lib/debug/.build-id/.*\.debug.*")
+  endif()
+
+  if(GENERATOR_TYPE STREQUAL "RPM")
+    set(EXPECTED_FILE_5 "libs-DebugInfoPackage.rpm")
+    set(EXPECTED_FILE_CONTENT_5 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/test_lib.cpp.*\.debug.*")
+  elseif(GENERATOR_TYPE STREQUAL "DEB")
+    set(EXPECTED_FILE_5 "TestDinfo-pkg-libs-dbgsym.ddeb")
+    set(EXPECTED_FILE_CONTENT_5 ".*/usr/lib/debug/.build-id/.*\.debug.*")
+  endif()
+
+  set(EXPECTED_FILE_6 "TestDinfo-pkg*-appheaders.${PKG}")
+  set(EXPECTED_FILE_CONTENT_6_LIST "/include;/include/test_lib.hpp")
 
-set(EXPECTED_FILE_6 "TestDinfo-pkg*-appheaders.${PKG}")
-set(EXPECTED_FILE_CONTENT_6_LIST "/include;/include/test_lib.hpp")
+elseif(PACKAGING_TYPE STREQUAL "MONOLITHIC" AND GENERATOR_TYPE STREQUAL "DEB")
+  set(EXPECTED_FILES_COUNT "2")
+
+  set(EXPECTED_FILE_1 "TestDinfo-pkg.deb")
+  set(
+    EXPECTED_FILE_CONTENT_1_LIST
+    "/bar;/bar/CMakeLists.txt;/bas;/bas/libtest_lib.so;/foo;/foo/test_prog;/include;/include/test_lib.hpp"
+  )
+
+  set(EXPECTED_FILE_2 "TestDinfo-pkg-dbgsym.ddeb")
+  set(EXPECTED_FILE_CONTENT_2 ".*/usr/lib/debug/.build-id/.*\.debug.*")
+
+endif()
index 9ff1f8a..e9cebbf 100644 (file)
@@ -28,6 +28,8 @@ 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_DEBIAN_DEBUGINFO_PACKAGE ON)
+
 set(CPACK_RPM_APPLICATIONS_FILE_NAME "RPM-DEFAULT")
 set(CPACK_RPM_APPLICATIONS_DEBUGINFO_PACKAGE ON)
 set(CPACK_DEBIAN_APPLICATIONS_FILE_NAME "DEB-DEFAULT")
index 37360e8..8b6ca94 100644 (file)
@@ -1,6 +1,6 @@
 CPack Warning: Adding file to tar:
-#top level directory: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/_CPack_Packages/Linux/DEB/extra-0.1.1-Linux/bas
+#top level directory: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/_CPack_Packages/[^/]+/DEB/extra-0.1.1-[^/]+/bas
 #missing file: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/conffiles
 CPack Warning: Adding file to tar:
-#top level directory: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/_CPack_Packages/Linux/DEB/extra-0.1.1-Linux/foo
+#top level directory: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/_CPack_Packages/[^/]+/DEB/extra-0.1.1-[^/]+/foo
 #missing file: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/conffiles
index d1a3a5f..f859215 100644 (file)
@@ -1,2 +1,2 @@
 set(EXPECTED_FILES_COUNT "1")
-set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
+set(EXPECTED_FILE_CONTENT_1_LIST "/bar;/bar/CMakeLists.txt;/baz;/baz/CMakeLists.txt;/foo;/foo/CMakeLists.txt")
index fbdda9c..13af097 100644 (file)
@@ -1,3 +1,4 @@
 set(whitespaces_ "[\t\n\r ]*")
-set(md5sums_md5sums "^.* usr/foo/CMakeLists\.txt${whitespaces_}$")
+set(hashsyms_ "[a-f0-9]+")
+set(md5sums_md5sums "^${hashsyms_}  usr/bar/CMakeLists\.txt${whitespaces_}${hashsyms_}  usr/baz/CMakeLists\.txt${whitespaces_}${hashsyms_}  usr/foo/CMakeLists\.txt${whitespaces_}$")
 verifyDebControl("${FOUND_FILE_1}" "md5sums" "md5sums")
index 15c5892..3c922d2 100644 (file)
@@ -1,4 +1,6 @@
 install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+install(FILES CMakeLists.txt DESTINATION bar COMPONENT test)
+install(FILES CMakeLists.txt DESTINATION baz COMPONENT test)
 
 if(PACKAGING_TYPE STREQUAL "COMPONENT")
   set(CPACK_COMPONENTS_ALL test)
diff --git a/Tests/RunCMake/CommandLine/DeprecateVS10-WARN-OFF.cmake b/Tests/RunCMake/CommandLine/DeprecateVS10-WARN-OFF.cmake
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/CommandLine/DeprecateVS10-WARN-ON-stderr.txt b/Tests/RunCMake/CommandLine/DeprecateVS10-WARN-ON-stderr.txt
new file mode 100644 (file)
index 0000000..202ef80
--- /dev/null
@@ -0,0 +1,5 @@
+^CMake Warning:
+  The "Visual Studio 10 2010" generator is deprecated and will be removed in
+  a future version of CMake.
+
+  Add CMAKE_WARN_VS10=OFF to the cache to disable this warning.$
diff --git a/Tests/RunCMake/CommandLine/DeprecateVS10-WARN-ON.cmake b/Tests/RunCMake/CommandLine/DeprecateVS10-WARN-ON.cmake
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/CommandLine/EnvBuildType-stdout.txt b/Tests/RunCMake/CommandLine/EnvBuildType-stdout.txt
new file mode 100644 (file)
index 0000000..03b92a7
--- /dev/null
@@ -0,0 +1,2 @@
+-- ENV{CMAKE_BUILD_TYPE}='BuildTypeEnv'
+-- CMAKE_BUILD_TYPE='BuildTypeEnv'
diff --git a/Tests/RunCMake/CommandLine/EnvBuildType.cmake b/Tests/RunCMake/CommandLine/EnvBuildType.cmake
new file mode 100644 (file)
index 0000000..e5e6d04
--- /dev/null
@@ -0,0 +1,2 @@
+message(STATUS "ENV{CMAKE_BUILD_TYPE}='$ENV{CMAKE_BUILD_TYPE}'")
+message(STATUS "CMAKE_BUILD_TYPE='${CMAKE_BUILD_TYPE}'")
diff --git a/Tests/RunCMake/CommandLine/EnvBuildTypeIgnore-stdout.txt b/Tests/RunCMake/CommandLine/EnvBuildTypeIgnore-stdout.txt
new file mode 100644 (file)
index 0000000..4a26732
--- /dev/null
@@ -0,0 +1,2 @@
+-- ENV{CMAKE_BUILD_TYPE}='BuildTypeEnv'
+-- CMAKE_BUILD_TYPE='BuildTypeOpt'
diff --git a/Tests/RunCMake/CommandLine/EnvBuildTypeIgnore.cmake b/Tests/RunCMake/CommandLine/EnvBuildTypeIgnore.cmake
new file mode 100644 (file)
index 0000000..f21666f
--- /dev/null
@@ -0,0 +1 @@
+include(EnvBuildType.cmake)
diff --git a/Tests/RunCMake/CommandLine/EnvConfigTypes-stdout.txt b/Tests/RunCMake/CommandLine/EnvConfigTypes-stdout.txt
new file mode 100644 (file)
index 0000000..bfec18f
--- /dev/null
@@ -0,0 +1,2 @@
+-- ENV{CMAKE_CONFIGURATION_TYPES}='ConfigTypesEnv'
+-- CMAKE_CONFIGURATION_TYPES='ConfigTypesEnv'
diff --git a/Tests/RunCMake/CommandLine/EnvConfigTypes.cmake b/Tests/RunCMake/CommandLine/EnvConfigTypes.cmake
new file mode 100644 (file)
index 0000000..8c9b63a
--- /dev/null
@@ -0,0 +1,2 @@
+message(STATUS "ENV{CMAKE_CONFIGURATION_TYPES}='$ENV{CMAKE_CONFIGURATION_TYPES}'")
+message(STATUS "CMAKE_CONFIGURATION_TYPES='${CMAKE_CONFIGURATION_TYPES}'")
diff --git a/Tests/RunCMake/CommandLine/EnvConfigTypesIgnore-stdout.txt b/Tests/RunCMake/CommandLine/EnvConfigTypesIgnore-stdout.txt
new file mode 100644 (file)
index 0000000..7800a4f
--- /dev/null
@@ -0,0 +1,2 @@
+-- ENV{CMAKE_CONFIGURATION_TYPES}='ConfigTypesEnv'
+-- CMAKE_CONFIGURATION_TYPES='ConfigTypesOpt'
diff --git a/Tests/RunCMake/CommandLine/EnvConfigTypesIgnore.cmake b/Tests/RunCMake/CommandLine/EnvConfigTypesIgnore.cmake
new file mode 100644 (file)
index 0000000..fcbbaea
--- /dev/null
@@ -0,0 +1 @@
+include(EnvConfigTypes.cmake)
index c58b1d0..dc066f1 100644 (file)
@@ -344,6 +344,26 @@ if(RunCMake_GENERATOR MATCHES "Unix Makefiles" OR RunCMake_GENERATOR MATCHES "Ni
   run_EnvironmentExportCompileCommands()
 endif()
 
+function(run_EnvironmentBuildType)
+  set(ENV{CMAKE_BUILD_TYPE} "BuildTypeEnv")
+  run_cmake(EnvBuildType)
+  run_cmake_with_options(EnvBuildTypeIgnore -DCMAKE_BUILD_TYPE=BuildTypeOpt)
+  unset(ENV{CMAKE_BUILD_TYPE})
+endfunction()
+
+function(run_EnvironmentConfigTypes)
+  set(ENV{CMAKE_CONFIGURATION_TYPES} "ConfigTypesEnv")
+  run_cmake(EnvConfigTypes)
+  run_cmake_with_options(EnvConfigTypesIgnore -DCMAKE_CONFIGURATION_TYPES=ConfigTypesOpt)
+  unset(ENV{CMAKE_CONFIGURATION_TYPES})
+endfunction()
+
+if(RunCMake_GENERATOR MATCHES "Make|^Ninja$")
+  run_EnvironmentBuildType()
+elseif(RunCMake_GENERATOR MATCHES "Ninja Multi-Config|Visual Studio|Xcode")
+  run_EnvironmentConfigTypes()
+endif()
+
 function(run_EnvironmentToolchain)
   set(ENV{CMAKE_TOOLCHAIN_FILE} "${RunCMake_SOURCE_DIR}/EnvToolchain-toolchain.cmake")
   run_cmake(EnvToolchainAbsolute)
@@ -627,9 +647,10 @@ run_cmake_command(E_cat_directory
 
 file(WRITE "${out}/first_file.txt" "first file to append\n")
 file(WRITE "${out}/second_file.txt" "second file to append\n")
+file(WRITE "${out}/empty_file.txt" "")
 file(WRITE "${out}/unicode_file.txt" "àéùç - í•œêµ­ì–´") # Korean in Korean
 run_cmake_command(E_cat_good_cat
-  ${CMAKE_COMMAND} -E cat "${out}/first_file.txt" "${out}/second_file.txt" "${out}/unicode_file.txt")
+  ${CMAKE_COMMAND} -E cat "${out}/first_file.txt" "${out}/second_file.txt" "${out}/empty_file.txt" "${out}/unicode_file.txt")
 unset(out)
 
 run_cmake_command(E_cat_good_binary_cat
@@ -898,3 +919,10 @@ set(ProfilingTestOutput ${RunCMake_TEST_BINARY_DIR}/output.json)
 set(RunCMake_TEST_OPTIONS --profiling-format=google-trace --profiling-output=${ProfilingTestOutput})
 run_cmake(ProfilingTest)
 unset(RunCMake_TEST_OPTIONS)
+
+if(RunCMake_GENERATOR MATCHES "^Visual Studio 10 2010")
+  run_cmake_with_options(DeprecateVS10-WARN-ON -DCMAKE_WARN_VS10=ON)
+  unset(ENV{CMAKE_WARN_VS10})
+  run_cmake(DeprecateVS10-WARN-ON)
+  run_cmake_with_options(DeprecateVS10-WARN-OFF -DCMAKE_WARN_VS10=OFF)
+endif()
diff --git a/Tests/RunCMake/CompileFeatures/CMP0128WarnMatch-stderr.txt b/Tests/RunCMake/CompileFeatures/CMP0128WarnMatch-stderr.txt
new file mode 100644 (file)
index 0000000..320c2ba
--- /dev/null
@@ -0,0 +1,8 @@
+CMake Warning \(dev\) in CMakeLists\.txt:
+  Policy CMP0128 is not set: Selection of language standard and extension
+  flags improved\.  Run "cmake --help-policy CMP0128" for policy details\.  Use
+  the cmake_policy command to set the policy and suppress this warning\.
+
+  For compatibility with older versions of CMake, unnecessary flags for
+  language standard or compiler extensions may be added.
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/CompileFeatures/CMP0128WarnMatch.cmake b/Tests/RunCMake/CompileFeatures/CMP0128WarnMatch.cmake
new file mode 100644 (file)
index 0000000..0a5606a
--- /dev/null
@@ -0,0 +1,7 @@
+enable_language(@lang@)
+cmake_policy(SET CMP0128 OLD)
+set(CMAKE_POLICY_WARNING_CMP0128 ON)
+
+set(CMAKE_@lang@_EXTENSIONS @extensions_default@)
+set(CMAKE_@lang@_STANDARD @standard_default@)
+add_library(foo "@RunCMake_SOURCE_DIR@/empty.@ext@")
diff --git a/Tests/RunCMake/CompileFeatures/CMP0128WarnUnset-stderr.txt b/Tests/RunCMake/CompileFeatures/CMP0128WarnUnset-stderr.txt
new file mode 100644 (file)
index 0000000..068cba9
--- /dev/null
@@ -0,0 +1,8 @@
+CMake Warning \(dev\) in CMakeLists\.txt:
+  Policy CMP0128 is not set: Selection of language standard and extension
+  flags improved\.  Run "cmake --help-policy CMP0128" for policy details\.  Use
+  the cmake_policy command to set the policy and suppress this warning\.
+
+  For compatibility with older versions of CMake, compiler extensions won't
+  be @opposite@\.
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/CompileFeatures/CMP0128WarnUnset.cmake b/Tests/RunCMake/CompileFeatures/CMP0128WarnUnset.cmake
new file mode 100644 (file)
index 0000000..cd7af2c
--- /dev/null
@@ -0,0 +1,6 @@
+enable_language(@lang@)
+cmake_policy(SET CMP0128 OLD)
+set(CMAKE_POLICY_WARNING_CMP0128 ON)
+
+set(CMAKE_@lang@_EXTENSIONS @extensions_opposite@)
+add_library(foo "@RunCMake_SOURCE_DIR@/empty.@ext@")
diff --git a/Tests/RunCMake/CompileFeatures/ExtensionsStandardDefault-build-check.cmake b/Tests/RunCMake/CompileFeatures/ExtensionsStandardDefault-build-check.cmake
new file mode 100644 (file)
index 0000000..4e85397
--- /dev/null
@@ -0,0 +1,12 @@
+foreach(flag @flags@)
+  string(FIND "${actual_stdout}" "${flag}" position)
+
+  if(NOT position EQUAL -1)
+    set(found TRUE)
+    break()
+  endif()
+endforeach()
+
+if(NOT found)
+  set(RunCMake_TEST_FAILED "No compile flags from \"@flags@\" found for LANG_STANDARD=default and @lang@_EXTENSIONS=@extensions_opposite@.")
+endif()
diff --git a/Tests/RunCMake/CompileFeatures/ExtensionsStandardDefault.cmake b/Tests/RunCMake/CompileFeatures/ExtensionsStandardDefault.cmake
new file mode 100644 (file)
index 0000000..32578d1
--- /dev/null
@@ -0,0 +1,9 @@
+enable_language(@lang@)
+
+# Make sure the compile command is not hidden.
+string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_@lang@_COMPILE_OBJECT "${CMAKE_@lang@_COMPILE_OBJECT}")
+string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_@lang@_COMPILE_OBJECT "${CMAKE_@lang@_COMPILE_OBJECT}")
+
+set(CMAKE_@lang@_EXTENSIONS @extensions_opposite@)
+set(CMAKE_@lang@_STANDARD @standard_default@)
+add_library(foo "@RunCMake_SOURCE_DIR@/empty.@ext@")
diff --git a/Tests/RunCMake/CompileFeatures/ExtensionsStandardUnset-build-check.cmake b/Tests/RunCMake/CompileFeatures/ExtensionsStandardUnset-build-check.cmake
new file mode 100644 (file)
index 0000000..abe293c
--- /dev/null
@@ -0,0 +1,12 @@
+foreach(flag @flags@)
+  string(FIND "${actual_stdout}" "${flag}" position)
+
+  if(NOT position EQUAL -1)
+    set(found TRUE)
+    break()
+  endif()
+endforeach()
+
+if(NOT found)
+  set(RunCMake_TEST_FAILED "No compile flags from \"@flags@\" found for CMAKE_@lang@_EXTENSIONS=@extensions_opposite@.")
+endif()
diff --git a/Tests/RunCMake/CompileFeatures/ExtensionsStandardUnset.cmake b/Tests/RunCMake/CompileFeatures/ExtensionsStandardUnset.cmake
new file mode 100644 (file)
index 0000000..99bb3f0
--- /dev/null
@@ -0,0 +1,8 @@
+enable_language(@lang@)
+
+# Make sure the compile command is not hidden.
+string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_@lang@_COMPILE_OBJECT "${CMAKE_@lang@_COMPILE_OBJECT}")
+string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_@lang@_COMPILE_OBJECT "${CMAKE_@lang@_COMPILE_OBJECT}")
+
+set(CMAKE_@lang@_EXTENSIONS @extensions_opposite@)
+add_library(foo "@RunCMake_SOURCE_DIR@/empty.@ext@")
diff --git a/Tests/RunCMake/CompileFeatures/NoUnnecessaryFlag-build-check.cmake b/Tests/RunCMake/CompileFeatures/NoUnnecessaryFlag-build-check.cmake
new file mode 100644 (file)
index 0000000..4f767fa
--- /dev/null
@@ -0,0 +1,8 @@
+foreach(flag @flags@)
+  string(FIND "${actual_stdout}" "${flag}" position)
+
+  if(NOT position EQUAL -1)
+    set(RunCMake_TEST_FAILED "\"${flag}\" compile flag found.")
+    break()
+  endif()
+endforeach()
diff --git a/Tests/RunCMake/CompileFeatures/NoUnnecessaryFlag.cmake b/Tests/RunCMake/CompileFeatures/NoUnnecessaryFlag.cmake
new file mode 100644 (file)
index 0000000..8ef3a72
--- /dev/null
@@ -0,0 +1,9 @@
+enable_language(@lang@)
+
+# Make sure the compile command is not hidden.
+string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_@lang@_COMPILE_OBJECT "${CMAKE_@lang@_COMPILE_OBJECT}")
+string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_@lang@_COMPILE_OBJECT "${CMAKE_@lang@_COMPILE_OBJECT}")
+
+set(CMAKE_@lang@_EXTENSIONS @extensions_default@)
+set(CMAKE_@lang@_STANDARD @standard_default@)
+add_library(foo "@RunCMake_SOURCE_DIR@/empty.@ext@")
index 5a70da2..ebd981b 100644 (file)
@@ -9,17 +9,8 @@ run_cmake(NotAFeature_OriginDebugGenex)
 run_cmake(NotAFeature_OriginDebugTransitive)
 run_cmake(NotAFeature_OriginDebugCommand)
 
-run_cmake(generate_feature_list)
-file(READ
-  "${RunCMake_BINARY_DIR}/generate_feature_list-build/c_features.txt"
-  C_FEATURES
-)
-file(READ
-  "${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx_features.txt"
-  CXX_FEATURES
-)
-include("${RunCMake_BINARY_DIR}/generate_feature_list-build/c_standard_default.cmake")
-include("${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx_standard_default.cmake")
+run_cmake(compiler_introspection)
+include("${RunCMake_BINARY_DIR}/compiler_introspection-build/info.cmake")
 
 if (NOT C_FEATURES)
   run_cmake(NoSupportedCFeatures)
@@ -43,21 +34,139 @@ elseif (cxx_std_98 IN_LIST CXX_FEATURES AND cxx_std_11 IN_LIST CXX_FEATURES)
   unset(RunCMake_TEST_OPTIONS)
 endif()
 
+configure_file("${RunCMake_SOURCE_DIR}/CMakeLists.txt" "${RunCMake_BINARY_DIR}/CMakeLists.txt" COPYONLY)
+
+function(test_build)
+  set(test ${name}-${lang})
+
+  configure_file("${RunCMake_SOURCE_DIR}/${name}.cmake" "${RunCMake_BINARY_DIR}/${test}.cmake" @ONLY)
+  if(EXISTS "${RunCMake_SOURCE_DIR}/${name}-build-check.cmake")
+    configure_file("${RunCMake_SOURCE_DIR}/${name}-build-check.cmake" "${RunCMake_BINARY_DIR}/${test}-build-check.cmake" @ONLY)
+  endif()
+  if(EXISTS "${RunCMake_SOURCE_DIR}/${name}-stderr.txt")
+    configure_file("${RunCMake_SOURCE_DIR}/${name}-stderr.txt" "${RunCMake_BINARY_DIR}/${test}-stderr.txt" @ONLY)
+  endif()
+
+  set(RunCMake_SOURCE_DIR "${RunCMake_BINARY_DIR}")
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${test}-build")
+  run_cmake(${test})
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(${test}-build ${CMAKE_COMMAND} --build . ${ARGN})
+endfunction()
+
+# Mangle flags such as they're in verbose build output.
+macro(mangle_flags variable)
+  set(result "${${variable}}")
+
+  if(RunCMake_GENERATOR MATCHES "Visual Studio" AND MSVC_TOOLSET_VERSION GREATER_EQUAL 141)
+    string(REPLACE "-" "/" result "${result}")
+  elseif(RunCMake_GENERATOR STREQUAL "Xcode" AND CMAKE_XCODE_BUILD_SYSTEM GREATER_EQUAL 12)
+    string(REPLACE "=" [[\\=]] result "${result}")
+  endif()
+
+  string(REPLACE ";" " " result "${result}")
+  list(APPEND flags "${result}")
+endmacro()
+
+function(test_extensions_opposite)
+  if(extensions_opposite)
+    set(flag_ext "_EXT")
+  endif()
+
+  set(flag "${${lang}${${lang}_STANDARD_DEFAULT}${flag_ext}_FLAG}")
+
+  if(NOT flag)
+    return()
+  endif()
+
+  mangle_flags(flag)
+
+  # Make sure we enable/disable extensions when:
+  # 1. LANG_STANDARD is unset.
+  set(name ExtensionsStandardUnset)
+  set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0128=NEW)
+  test_build(--verbose)
+
+  # 2. LANG_STANDARD matches CMAKE_LANG_STANDARD_DEFAULT.
+  set(name ExtensionsStandardDefault)
+  test_build(--verbose)
+endfunction()
+
+function(test_no_unnecessary_flag)
+  set(standard_flag "${${lang}${${lang}_STANDARD_DEFAULT}_FLAG}")
+  set(extension_flag "${${lang}${${lang}_STANDARD_DEFAULT}_EXT_FLAG}")
+
+  if(NOT standard_flag AND NOT extension_flag)
+    return()
+  endif()
+
+  mangle_flags(standard_flag)
+  mangle_flags(extension_flag)
+
+  set(name NoUnnecessaryFlag)
+  set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0128=NEW)
+  test_build(--verbose)
+endfunction()
+
+function(test_cmp0128_warn_match)
+  set(name CMP0128WarnMatch)
+  test_build()
+endfunction()
+
+function(test_cmp0128_warn_unset)
+  # For compilers that had CMAKE_<LANG>_EXTENSION_COMPILE_OPTION (only IAR)
+  # there is no behavioural change and thus no warning.
+  if(NOT "${${lang}_EXT_FLAG}" STREQUAL "")
+    return()
+  endif()
+
+  if(extensions_opposite)
+    set(opposite "enabled")
+  else()
+    set(opposite "disabled")
+  endif()
+
+  set(name CMP0128WarnUnset)
+  test_build()
+endfunction()
+
+function(test_lang lang ext)
+  if(CMake_NO_${lang}_STANDARD)
+    return()
+  endif()
+
+  set(extensions_default "${${lang}_EXTENSIONS_DEFAULT}")
+  set(standard_default "${${lang}_STANDARD_DEFAULT}")
+
+  if(extensions_default)
+    set(extensions_opposite OFF)
+  else()
+    set(extensions_opposite ON)
+  endif()
+
+  test_extensions_opposite()
+  test_no_unnecessary_flag()
+  test_cmp0128_warn_match()
+  test_cmp0128_warn_unset()
+endfunction()
+
+if(C_STANDARD_DEFAULT)
+  test_lang(C c)
+endif()
+
 if(CXX_STANDARD_DEFAULT)
   run_cmake(NotAStandard)
 
   foreach(standard 98 11)
-    file(READ
-      "${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx${standard}_flag.txt"
-      CXX${standard}_FLAG
-    )
     if (CXX${standard}_FLAG STREQUAL NOTFOUND)
       run_cmake(RequireCXX${standard})
       run_cmake(RequireCXX${standard}Variable)
     endif()
-    if (CXX${standard}EXT_FLAG STREQUAL NOTFOUND)
+    if (CXX${standard}_EXT_FLAG STREQUAL NOTFOUND)
       run_cmake(RequireCXX${standard}Ext)
       run_cmake(RequireCXX${standard}ExtVariable)
     endif()
   endforeach()
+
+  test_lang(CXX cpp)
 endif()
diff --git a/Tests/RunCMake/CompileFeatures/compiler_introspection.cmake b/Tests/RunCMake/CompileFeatures/compiler_introspection.cmake
new file mode 100644 (file)
index 0000000..5691344
--- /dev/null
@@ -0,0 +1,38 @@
+enable_language(C CXX)
+
+set(info "")
+
+if(MSVC_TOOLSET_VERSION)
+  string(APPEND info "
+set(MSVC_TOOLSET_VERSION ${MSVC_TOOLSET_VERSION})
+
+")
+endif()
+
+if(CMAKE_XCODE_BUILD_SYSTEM)
+  string(APPEND info "
+set(CMAKE_XCODE_BUILD_SYSTEM ${CMAKE_XCODE_BUILD_SYSTEM})
+
+")
+endif()
+
+macro(info lang)
+  string(APPEND info "\
+set(${lang}_STANDARD_DEFAULT ${CMAKE_${lang}_STANDARD_DEFAULT})
+set(${lang}_EXTENSIONS_DEFAULT ${CMAKE_${lang}_EXTENSIONS_DEFAULT})
+set(${lang}_FEATURES ${CMAKE_${lang}_COMPILE_FEATURES})
+
+set(${lang}_EXT_FLAG ${CMAKE_${lang}_EXTENSION_COMPILE_OPTION})
+")
+
+  foreach(standard ${ARGN})
+    string(APPEND info "\
+set(${lang}${standard}_FLAG ${CMAKE_${lang}${standard}_STANDARD_COMPILE_OPTION})
+set(${lang}${standard}_EXT_FLAG ${CMAKE_${lang}${standard}_EXTENSION_COMPILE_OPTION})
+")
+  endforeach()
+endmacro()
+
+info(C 90 99 11 17 23)
+info(CXX 98 11 14 17 20 23)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "${info}")
index 11ec041..8d91e77 100644 (file)
@@ -1,7 +1,7 @@
 #ifdef _WIN32
 __declspec(dllexport)
 #endif
-  int empty()
+  int empty(void)
 {
   return 0;
 }
diff --git a/Tests/RunCMake/CompileFeatures/generate_feature_list.cmake b/Tests/RunCMake/CompileFeatures/generate_feature_list.cmake
deleted file mode 100644 (file)
index 5c58052..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-
-enable_language(C)
-
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/c_features.txt"
-  "${CMAKE_C_COMPILE_FEATURES}"
-)
-
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx_features.txt"
-  "${CMAKE_CXX_COMPILE_FEATURES}"
-)
-
-if(DEFINED CMAKE_C_STANDARD_DEFAULT)
-  set(c_standard_default_code "set(C_STANDARD_DEFAULT \"${CMAKE_C_STANDARD_DEFAULT}\")\n")
-else()
-  set(c_standard_default_code "unset(C_STANDARD_DEFAULT)\n")
-endif()
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/c_standard_default.cmake" "${c_standard_default_code}")
-
-if(DEFINED CMAKE_CXX_STANDARD_DEFAULT)
-  set(cxx_standard_default_code "set(CXX_STANDARD_DEFAULT \"${CMAKE_CXX_STANDARD_DEFAULT}\")\n")
-else()
-  set(cxx_standard_default_code "unset(CXX_STANDARD_DEFAULT)\n")
-endif()
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx_standard_default.cmake" "${cxx_standard_default_code}")
-
-foreach(standard 98 11)
-  set(CXX${standard}_FLAG NOTFOUND)
-  if (DEFINED CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION)
-    set(CXX${standard}_FLAG ${CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION})
-  endif()
-
-  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx${standard}_flag.txt"
-    "${CXX${standard}_FLAG}"
-  )
-  set(CXX${standard}EXT_FLAG NOTFOUND)
-  if (DEFINED CMAKE_CXX${standard}_EXTENSION_COMPILE_OPTION)
-    set(CXX${standard}EXT_FLAG ${CMAKE_CXX${standard}_EXTENSION_COMPILE_OPTION})
-  endif()
-
-  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx${standard}ext_flag.txt"
-    "${CXX${standard}EXT_FLAG}"
-  )
-endforeach()
index 9baeab7..e83c45e 100644 (file)
@@ -9,6 +9,7 @@ run_cmake(DownloadTwice)
 run_cmake(DownloadFile)
 run_cmake(SameGenerator)
 run_cmake(VarDefinitions)
+run_cmake(VarPassthroughs)
 run_cmake(GetProperties)
 run_cmake(UsesTerminalOverride)
 run_cmake(MakeAvailable)
diff --git a/Tests/RunCMake/FetchContent/VarPassthroughs.cmake b/Tests/RunCMake/FetchContent/VarPassthroughs.cmake
new file mode 100644 (file)
index 0000000..ad743d8
--- /dev/null
@@ -0,0 +1,38 @@
+include(FetchContent)
+
+set(CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY AAAA)
+set(CMAKE_TLS_VERIFY BBBB)
+set(CMAKE_TLS_CAINFO CCCC)
+set(CMAKE_NETRC DDDD)
+set(CMAKE_NETRC_FILE EEEE)
+
+FetchContent_Declare(PassThrough
+  DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "Download command executed"
+)
+FetchContent_Populate(PassThrough)
+
+set(gen_file ${FETCHCONTENT_BASE_DIR}/passthrough-subbuild/CMakeLists.txt)
+if(NOT EXISTS ${gen_file})
+  message(FATAL_ERROR "File does not exist: ${gen_file}")
+endif()
+file(READ ${gen_file} contents)
+
+if(NOT contents MATCHES "CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY \\[==\\[AAAA\\]==\\]")
+  message(FATAL_ERROR "Missing CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY")
+endif()
+
+if(NOT contents MATCHES "CMAKE_TLS_VERIFY \\[==\\[BBBB\\]==\\]")
+  message(FATAL_ERROR "Missing CMAKE_TLS_VERIFY")
+endif()
+
+if(NOT contents MATCHES "CMAKE_TLS_CAINFO \\[==\\[CCCC\\]==\\]")
+  message(FATAL_ERROR "Missing CMAKE_TLS_CAINFO")
+endif()
+
+if(NOT contents MATCHES "CMAKE_NETRC \\[==\\[DDDD\\]==\\]")
+  message(FATAL_ERROR "Missing CMAKE_NETRC")
+endif()
+
+if(NOT contents MATCHES "CMAKE_NETRC_FILE \\[==\\[EEEE\\]==\\]")
+  message(FATAL_ERROR "Missing CMAKE_NETRC_FILE")
+endif()
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_MATCHING_ARGN.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_GET_MATCHING_ARGN.cmake
new file mode 100644 (file)
index 0000000..e49ff22
--- /dev/null
@@ -0,0 +1,17 @@
+if(WIN32)
+    set(ENV{PKG_CONFIG} "\"${CMAKE_CURRENT_SOURCE_DIR}\\dummy-pkg-config.bat\" --static --print-errors")
+else()
+    set(ENV{PKG_CONFIG} "\"${CMAKE_CURRENT_SOURCE_DIR}/dummy-pkg-config.sh\" --static --print-errors")
+endif()
+
+find_package(PkgConfig REQUIRED)
+
+if(NOT PKG_CONFIG_ARGN STREQUAL "--static;--print-errors")
+  message(SEND_ERROR "PKG_CONFIG_ARGN has wrong value '${PKG_CONFIG_ARGN}'")
+endif()
+
+_pkgconfig_invoke("none" "prefix" "output" "")
+
+if(NOT prefix_output STREQUAL "Received;--static;Received;--print-errors")
+  message(SEND_ERROR "prefix_output has wrong value '${prefix_output}'")
+endif()
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH-stdout.txt b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH-stdout.txt
new file mode 100644 (file)
index 0000000..6615d80
--- /dev/null
@@ -0,0 +1,3 @@
+-- ZOT_LIBRARIES='zot'
+-- ZOT_LINK_LIBRARIES='[^']*/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH-build/zot/lib/prefix-zot-suffix'
+-- ZOT_LDFLAGS='-L[^']*/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH-build/zot/lib;-lzot'
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH.cmake
new file mode 100644 (file)
index 0000000..9f654b5
--- /dev/null
@@ -0,0 +1,29 @@
+find_package(PkgConfig REQUIRED)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/zot/lib/pkgconfig/zot.pc" "
+prefix=${CMAKE_CURRENT_BINARY_DIR}/zot
+libdir=\${prefix}/lib
+
+Name: Zot
+Description: Dummy packaget to test LIBRARY_DIR support
+Version: 1.0
+Libs: -L\${libdir} -lzot
+")
+
+# Create a "library" file to find in libdir.
+set(CMAKE_FIND_LIBRARY_PREFIXES "prefix-")
+set(CMAKE_FIND_LIBRARY_SUFFIXES "-suffix")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/zot/lib/prefix-zot-suffix")
+
+# 'pkg-config --libs' drops -L flags in PKG_CONFIG_SYSTEM_LIBRARY_PATH by default.
+set(ENV{PKG_CONFIG_SYSTEM_LIBRARY_PATH} "${CMAKE_CURRENT_BINARY_DIR}/zot/lib")
+
+# 'pkgconf --libs' also drops -L flags in LIBRARY_PATH by default.
+set(ENV{LIBRARY_PATH}                   "${CMAKE_CURRENT_BINARY_DIR}/zot/lib")
+
+set(ENV{PKG_CONFIG_PATH}                "${CMAKE_CURRENT_BINARY_DIR}/zot/lib/pkgconfig")
+pkg_check_modules(ZOT REQUIRED zot)
+
+message(STATUS "ZOT_LIBRARIES='${ZOT_LIBRARIES}'")
+message(STATUS "ZOT_LINK_LIBRARIES='${ZOT_LINK_LIBRARIES}'")
+message(STATUS "ZOT_LDFLAGS='${ZOT_LDFLAGS}'")
index 78ccd96..f36d1eb 100644 (file)
@@ -13,6 +13,7 @@ run_cmake(FindPkgConfig_PKGCONFIG_PATH)
 run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_PATH)
 run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_ENVIRONMENT_PATH)
 run_cmake(FindPkgConfig_extract_frameworks)
+run_cmake(FindPkgConfig_GET_MATCHING_ARGN)
 
 if(APPLE)
   run_cmake(FindPkgConfig_extract_frameworks_target)
@@ -31,4 +32,8 @@ if (PKG_CONFIG_FOUND)
   run_cmake(FindPkgConfig_VERSION_OPERATORS)
   run_cmake(FindPkgConfig_GET_MATCHING_MODULE_NAME)
   run_cmake(FindPkgConfig_empty_target)
+
+  if(NOT RunCMake_BINARY_DIR MATCHES " ")
+    run_cmake(FindPkgConfig_LIBRARY_PATH)
+  endif()
 endif ()
index 486977c..ed43f14 100755 (executable)
@@ -1,5 +1,10 @@
 @ECHO OFF\r
 \r
+rem variables to get around `--static --version` printing the received\r
+rem message and then version\r
+set static=false\r
+set print_errors=false\r
+\r
 :LOOP\r
 \r
 IF "%1"=="" (\r
@@ -21,7 +26,19 @@ IF "%1"=="--exists" (
     EXIT /B 0\r
   )\r
 )\r
+IF "%1"=="--static" (\r
+  set static=true\r
+)\r
+IF "%1"=="--print-errors" (\r
+  set print_errors=true\r
+)\r
 SHIFT\r
 IF NOT "%~1"=="" GOTO LOOP\r
 \r
+IF "%static%"=="true" ECHO Received --static\r
+IF "%print_errors%"=="true" ECHO Received --print-errors\r
+\r
+IF "%static%"=="true" GOTO :EOF\r
+IF "%print_errors%"=="true" GOTO :EOF\r
+\r
 EXIT /B 255\r
index 56bba30..4021bf7 100755 (executable)
@@ -4,6 +4,11 @@
 # to the --exists argument with the PKG_CONFIG_PATH environment variable
 # and returns 1 if they are different.
 
+# variables to get around `--static --version` printing the received
+# message and then version
+static=false
+print_errors=false
+
 while [ $# -gt 0 ]; do
   case $1 in
     --version)
@@ -17,7 +22,21 @@ while [ $# -gt 0 ]; do
       echo "Found:    ${PKG_CONFIG_PATH}"
       [ "${last}" = "${PKG_CONFIG_PATH}" ] && exit 0 || exit 1
       ;;
+    --static)
+      static=true
+      ;;
+    --print-errors)
+      print_errors=true
+      ;;
   esac
   shift
 done
+
+$static && echo "Received --static"
+$print_errors && echo "Received --print-errors"
+
+if $static || $print_errors; then
+  exit 0
+fi
+
 exit 255
diff --git a/Tests/RunCMake/GeneratorExpression/CMP0085-OLD-stderr.txt b/Tests/RunCMake/GeneratorExpression/CMP0085-OLD-stderr.txt
new file mode 100644 (file)
index 0000000..cae3679
--- /dev/null
@@ -0,0 +1,8 @@
+^CMake Deprecation Warning at CMakeLists.txt:[0-9]+ \(cmake_minimum_required\):
+  The OLD behavior for policy CMP0085 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.$
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change-basic-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change-basic-stdout.txt
new file mode 100644 (file)
index 0000000..385159d
--- /dev/null
@@ -0,0 +1,7 @@
+Test project .*/Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change
+  Test #1: basic\.case_foo
+  Test #2: basic\.case_bar
+  Test #3: basic\.disabled_case \(Disabled\)
+  Test #4: basic\.DISABLEDnot_really_case
+
+Total Tests: 4
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change-typed-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change-typed-stdout.txt
new file mode 100644 (file)
index 0000000..095fdcd
--- /dev/null
@@ -0,0 +1,5 @@
+Test project .*/Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change
+  Test #1: typed/short\.case
+  Test #2: typed/float\.case
+
+Total Tests: 2
@@ -1,10 +1,10 @@
 Test project .*
-    Start 20: skip_test.test1
-1/1 Test #20: skip_test.test1 \.+\*\*\*Skipped +[0-9.]+ sec
+    Start 36: skip_test.test1
+1/1 Test #36: skip_test.test1 \.+\*\*\*Skipped +[0-9.]+ sec
 
 100% tests passed, 0 tests failed out of 1
 
 Total Test time \(real\) = +[0-9.]+ sec
 
 The following tests did not run:
-.*20 - skip_test\.test1 \(Skipped\)
+.*36 - skip_test\.test1 \(Skipped\)
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-test3-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-test3-stdout.txt
new file mode 100644 (file)
index 0000000..cf08267
--- /dev/null
@@ -0,0 +1,16 @@
+Test project .*
+    Start 27: TEST:basic\.case_foo!3
+1/4 Test #27: TEST:basic\.case_foo!3 \.+ +Passed +[0-9.]+ sec
+    Start 28: TEST:basic\.case_bar!3
+2/4 Test #28: TEST:basic\.case_bar!3 \.+ +Passed +[0-9.]+ sec
+    Start 29: TEST:basic\.disabled_case!3
+3/4 Test #29: TEST:basic\.disabled_case!3 \.+\*+Not Run \(Disabled\) +[0-9.]+ sec
+    Start 30: TEST:basic\.DISABLEDnot_really_case!3
+4/4 Test #30: TEST:basic\.DISABLEDnot_really_case!3 \.+ +Passed +[0-9.]+ sec
+
+100% tests passed, 0 tests failed out of 3
+
+Total Test time \(real\) = +[0-9.]+ sec
+
+The following tests did not run:
+.*29 - TEST:basic.disabled_case!3 \(Disabled\)
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-test4-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-test4-stdout.txt
new file mode 100644 (file)
index 0000000..4a9d75b
--- /dev/null
@@ -0,0 +1,9 @@
+Test project .*
+    Start 31: TEST:typed/short\.case!4
+1/2 Test #31: TEST:typed/short\.case!4 \.+ +Passed +[0-9.]+ sec
+    Start 32: TEST:typed/float\.case!4
+2/2 Test #32: TEST:typed/float\.case!4 \.+ +Passed +[0-9.]+ sec
+
+100% tests passed, 0 tests failed out of 2
+
+Total Test time \(real\) = +[0-9.]+ sec
index 8efd117..221d6ad 100644 (file)
@@ -24,6 +24,24 @@ gtest_discover_tests(
   PROPERTIES LABELS TEST2
 )
 
+gtest_discover_tests(
+  fake_gtest
+  TEST_PREFIX TEST:
+  TEST_SUFFIX !3
+  TEST_FILTER basic*
+  EXTRA_ARGS how now "\"brown\" cow"
+  PROPERTIES LABELS TEST3
+)
+
+gtest_discover_tests(
+  fake_gtest
+  TEST_PREFIX TEST:
+  TEST_SUFFIX !4
+  TEST_FILTER typed*
+  EXTRA_ARGS how now "\"brown\" cow"
+  PROPERTIES LABELS TEST4
+)
+
 add_executable(no_tests_defined no_tests_defined.cpp)
 xcode_sign_adhoc(no_tests_defined)
 
diff --git a/Tests/RunCMake/GoogleTest/GoogleTestDiscoveryArgChange.cmake b/Tests/RunCMake/GoogleTest/GoogleTestDiscoveryArgChange.cmake
new file mode 100644 (file)
index 0000000..e4e13c5
--- /dev/null
@@ -0,0 +1,14 @@
+enable_language(CXX)
+include(GoogleTest)
+
+enable_testing()
+
+include(xcode_sign_adhoc.cmake)
+
+add_executable(fake_gtest fake_gtest.cpp)
+xcode_sign_adhoc(fake_gtest)
+
+gtest_discover_tests(
+  fake_gtest
+  TEST_FILTER "${TEST_FILTER}*"
+)
index 530c8ab..33a4b43 100644 (file)
@@ -1,5 +1,12 @@
 include(RunCMake)
 
+if(RunCMake_GENERATOR STREQUAL "Borland Makefiles" OR
+   RunCMake_GENERATOR STREQUAL "Watcom WMake")
+  set(fs_delay 3)
+else()
+  set(fs_delay 1.125)
+endif()
+
 function(run_GoogleTest DISCOVERY_MODE)
   # Use a single build tree for a few tests without cleaning.
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/GoogleTest-build)
@@ -40,6 +47,20 @@ function(run_GoogleTest DISCOVERY_MODE)
     --no-label-summary
   )
 
+  run_cmake_command(GoogleTest-test3
+    ${CMAKE_CTEST_COMMAND}
+    -C Debug
+    -L TEST3
+    --no-label-summary
+  )
+
+  run_cmake_command(GoogleTest-test4
+    ${CMAKE_CTEST_COMMAND}
+    -C Debug
+    -L TEST4
+    --no-label-summary
+  )
+
   run_cmake_command(GoogleTest-test-missing
     ${CMAKE_CTEST_COMMAND}
     -C Debug
@@ -139,6 +160,46 @@ function(run_GoogleTest_discovery_timeout DISCOVERY_MODE)
   )
 endfunction()
 
+function(run_GoogleTest_discovery_arg_change DISCOVERY_MODE)
+  # Use a single build tree for a few tests without cleaning.
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/GoogleTest-discovery-arg-change)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  run_cmake_with_options(GoogleTestDiscoveryArgChange
+    -DCMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE=${DISCOVERY_MODE}
+    -DTEST_FILTER=basic
+  )
+  run_cmake_command(GoogleTest-discovery-arg-change-build
+    ${CMAKE_COMMAND}
+    --build .
+    --config Release
+    --target fake_gtest
+  )
+  run_cmake_command(GoogleTest-discovery-arg-change-basic
+    ${CMAKE_CTEST_COMMAND}
+    -C Release
+    -N
+  )
+  execute_process(COMMAND ${CMAKE_COMMAND} -E sleep ${fs_delay}) # handle 1s resolution
+  run_cmake_with_options(GoogleTestDiscoveryArgChange
+    -DCMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE=${DISCOVERY_MODE}
+    -DTEST_FILTER=typed
+  )
+  run_cmake_command(GoogleTest-discovery-arg-change-build
+    ${CMAKE_COMMAND}
+    --build .
+    --config Release
+    --target fake_gtest
+  )
+  run_cmake_command(GoogleTest-discovery-arg-change-typed
+    ${CMAKE_CTEST_COMMAND}
+    -C Release
+    -N
+  )
+endfunction()
+
 function(run_GoogleTest_discovery_multi_config)
   # Use a single build tree for a few tests without cleaning.
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/GoogleTest-discovery-multi-config)
@@ -181,6 +242,10 @@ foreach(DISCOVERY_MODE POST_BUILD PRE_TEST)
   run_GoogleTestXML(${DISCOVERY_MODE})
   message("Testing ${DISCOVERY_MODE} discovery mode via DISCOVERY_MODE option...")
   run_GoogleTest_discovery_timeout(${DISCOVERY_MODE})
+  if(# VS 9 does not rebuild if POST_BUILD command changes.
+      NOT "${DISCOVERY_MODE};${RunCMake_GENERATOR}" MATCHES "^POST_BUILD;Visual Studio 9")
+    run_GoogleTest_discovery_arg_change(${DISCOVERY_MODE})
+  endif()
 endforeach()
 
 if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
index 1956c37..b2a5cb4 100644 (file)
@@ -7,27 +7,42 @@ int main(int argc, char** argv)
   // it only requires that we produces output in the expected format when
   // invoked with --gtest_list_tests. Thus, we fake that here. This allows us
   // to test the module without actually needing Google Test.
+  bool is_filtered =
+    argc > 2 && std::string(argv[2]).find("--gtest_filter=") == 0;
+  bool is_basic_only =
+    is_filtered && std::string(argv[2]).find("basic*") != std::string::npos;
+  bool is_typed_only =
+    is_filtered && std::string(argv[2]).find("typed*") != std::string::npos;
+
   if (argc > 1 && std::string(argv[1]) == "--gtest_list_tests") {
-    std::cout << "basic." << std::endl;
-    std::cout << "  case_foo" << std::endl;
-    std::cout << "  case_bar" << std::endl;
-    std::cout << "  DISABLED_disabled_case" << std::endl;
-    std::cout << "  DISABLEDnot_really_case" << std::endl;
-    std::cout << "DISABLED_disabled." << std::endl;
-    std::cout << "  case" << std::endl;
-    std::cout << "DISABLEDnotreally." << std::endl;
-    std::cout << "  case" << std::endl;
-    std::cout << "typed/0.  # TypeParam = short" << std::endl;
-    std::cout << "  case" << std::endl;
-    std::cout << "typed/1.  # TypeParam = float" << std::endl;
-    std::cout << "  case" << std::endl;
-    std::cout << "value/test." << std::endl;
-    std::cout << "  case/0  # GetParam() = 1" << std::endl;
-    std::cout << "  case/1  # GetParam() = \"foo\"" << std::endl;
-    std::cout << "param/special." << std::endl;
-    std::cout << "  case/0  # GetParam() = \"semicolon;\"" << std::endl;
-    std::cout << "  case/1  # GetParam() = \"backslash\\\"" << std::endl;
-    std::cout << "  case/2  # GetParam() = \"${var}\"" << std::endl;
+    if (!is_typed_only) {
+      std::cout << "basic." << std::endl;
+      std::cout << "  case_foo" << std::endl;
+      std::cout << "  case_bar" << std::endl;
+      std::cout << "  DISABLED_disabled_case" << std::endl;
+      std::cout << "  DISABLEDnot_really_case" << std::endl;
+    }
+    if (!is_basic_only && !is_typed_only) {
+      std::cout << "DISABLED_disabled." << std::endl;
+      std::cout << "  case" << std::endl;
+      std::cout << "DISABLEDnotreally." << std::endl;
+      std::cout << "  case" << std::endl;
+    }
+    if (!is_basic_only) {
+      std::cout << "typed/0.  # TypeParam = short" << std::endl;
+      std::cout << "  case" << std::endl;
+      std::cout << "typed/1.  # TypeParam = float" << std::endl;
+      std::cout << "  case" << std::endl;
+    }
+    if (!is_basic_only && !is_typed_only) {
+      std::cout << "value/test." << std::endl;
+      std::cout << "  case/0  # GetParam() = 1" << std::endl;
+      std::cout << "  case/1  # GetParam() = \"foo\"" << std::endl;
+      std::cout << "param/special." << std::endl;
+      std::cout << "  case/0  # GetParam() = \"semicolon;\"" << std::endl;
+      std::cout << "  case/1  # GetParam() = \"backslash\\\"" << std::endl;
+      std::cout << "  case/2  # GetParam() = \"${var}\"" << std::endl;
+    }
     return 0;
   }
 
diff --git a/Tests/RunCMake/Ninja/Qt5AutoMocDeps.cmake b/Tests/RunCMake/Ninja/Qt5AutoMocDeps.cmake
deleted file mode 100644 (file)
index 46b840f..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-enable_language(CXX)
-
-find_package(Qt5Core REQUIRED)
-
-set(CMAKE_AUTOMOC ON)
-
-add_library(simple_lib SHARED simple_lib.cpp)
-add_executable(app_with_qt app.cpp app_qt.cpp)
-target_link_libraries(app_with_qt PRIVATE simple_lib Qt5::Core)
-
-if(Qt5Widgets_DIR)
-  find_package(Qt5Widgets REQUIRED)
-  qt5_wrap_ui(_headers MyWindow.ui)
-  add_executable(app_with_widget app.cpp MyWindow.cpp ${_headers})
-  target_link_libraries(app_with_widget PRIVATE Qt5::Widgets)
-  target_include_directories(app_with_widget PRIVATE "${CMAKE_BINARY_DIR}")
-endif()
-
-add_subdirectory(QtSubDir1)
-add_subdirectory(QtSubDir2)
-add_subdirectory(QtSubDir3)
diff --git a/Tests/RunCMake/Ninja/QtAutoMocDeps.cmake b/Tests/RunCMake/Ninja/QtAutoMocDeps.cmake
new file mode 100644 (file)
index 0000000..c441169
--- /dev/null
@@ -0,0 +1,27 @@
+enable_language(CXX)
+
+set(QtX Qt${with_qt_version})
+
+find_package(${QtX} REQUIRED COMPONENTS Core)
+
+set(CMAKE_AUTOMOC ON)
+
+add_library(simple_lib SHARED simple_lib.cpp)
+add_executable(app_with_qt app.cpp app_qt.cpp)
+target_link_libraries(app_with_qt PRIVATE simple_lib ${QtX}::Core)
+
+if(${QtX}Widgets_DIR)
+  find_package(${QtX} REQUIRED COMPONENTS Widgets)
+  if(with_qt_version STREQUAL 5)
+    qt5_wrap_ui(_headers MyWindow.ui)
+  else()
+    qt_wrap_ui(_headers MyWindow.ui)
+  endif()
+  add_executable(app_with_widget app.cpp MyWindow.cpp ${_headers})
+  target_link_libraries(app_with_widget PRIVATE ${QtX}::Widgets)
+  target_include_directories(app_with_widget PRIVATE "${CMAKE_BINARY_DIR}")
+endif()
+
+add_subdirectory(QtSubDir1)
+add_subdirectory(QtSubDir2)
+add_subdirectory(QtSubDir3)
index 64016b6..3a12dcd 100644 (file)
@@ -1,4 +1,4 @@
 cmake_policy(SET CMP0116 OLD)
 
 add_executable(sub_exe_1 ../app.cpp)
-target_link_libraries(sub_exe_1 PRIVATE Qt5::Core)
+target_link_libraries(sub_exe_1 PRIVATE ${QtX}::Core)
index 3176426..a2f77e4 100644 (file)
@@ -1,4 +1,4 @@
 cmake_policy(SET CMP0116 NEW)
 
 add_executable(sub_exe_2 ../app.cpp)
-target_link_libraries(sub_exe_2 PRIVATE Qt5::Core)
+target_link_libraries(sub_exe_2 PRIVATE ${QtX}::Core)
index d38cfe0..70644fa 100644 (file)
@@ -1,2 +1,2 @@
 add_executable(sub_exe_3 ../app.cpp)
-target_link_libraries(sub_exe_3 PRIVATE Qt5::Core)
+target_link_libraries(sub_exe_3 PRIVATE ${QtX}::Core)
index 3f239b9..2a5b556 100644 (file)
@@ -319,12 +319,17 @@ function (run_ChangeBuildType)
 endfunction()
 run_ChangeBuildType()
 
-function(run_Qt5AutoMocDeps)
-  if(CMake_TEST_Qt5 AND CMAKE_TEST_Qt5Core_Version VERSION_GREATER_EQUAL 5.15.0)
-    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Qt5AutoMocDeps-build)
-    set(RunCMake_TEST_OPTIONS "-DQt5Core_DIR=${Qt5Core_DIR}" "-DQt5Widgets_DIR=${Qt5Widgets_DIR}")
-    run_cmake(Qt5AutoMocDeps)
-    unset(RunCMake_TEST_OPTIONS)
+function(run_QtAutoMocDeps)
+  set(QtX Qt${CMake_TEST_Qt_version})
+  if(CMake_TEST_${QtX}Core_Version VERSION_GREATER_EQUAL 5.15.0)
+    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/QtAutoMocDeps-build)
+    run_cmake_with_options(QtAutoMocDeps
+      "-Dwith_qt_version=${CMake_TEST_Qt_version}"
+      "-D${QtX}_DIR=${${QtX}_DIR}"
+      "-D${QtX}Core_DIR=${${QtX}Core_DIR}"
+      "-D${QtX}Widgets_DIR=${${QtX}Widgets_DIR}"
+      "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
+    )
     # Build the project.
     run_ninja("${RunCMake_TEST_BINARY_DIR}")
     # Touch just the library source file, which shouldn't cause a rerun of AUTOMOC
@@ -352,4 +357,6 @@ function(run_Qt5AutoMocDeps)
     run_ninja("${RunCMake_TEST_BINARY_DIR}")
   endif()
 endfunction()
-run_Qt5AutoMocDeps()
+if(CMake_TEST_Qt_version)
+  run_QtAutoMocDeps()
+endif()
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_target-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_target-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..80e9c2f
--- /dev/null
@@ -0,0 +1,2 @@
+^\[1/1\] Generating echo_depend_target\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Release[\/]echo(\.exe)?' 'Release'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_target-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_target-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..1a79877
--- /dev/null
@@ -0,0 +1,2 @@
+^\[1/1\] Generating echo_depend_target\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_target-release-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_target-release-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..80e9c2f
--- /dev/null
@@ -0,0 +1,2 @@
+^\[1/1\] Generating echo_depend_target\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Release[\/]echo(\.exe)?' 'Release'$
index bb68a50..2de5a3a 100644 (file)
@@ -143,6 +143,16 @@ add_custom_command(
     PROPERTY SYMBOLIC 1)
 add_custom_target(echo_dbgx DEPENDS "$<$<CONFIG:Debug>:echo_dbgx_Debug.txt>")
 
+# A non-cross-config custom command expresses target dependencies in command config.
+add_custom_command(
+  OUTPUT echo_depend_target.txt
+  COMMAND ${CMAKE_COMMAND} -E env $<TARGET_FILE:echo> $<CONFIG>
+  # A real project should do:
+  #   DEPENDS $<TARGET_FILE:echo>
+  # but here we are testing the target-level dependency implied by TARGET_FILE.
+  )
+add_custom_target(echo_depend_target DEPENDS echo_depend_target.txt)
+
 add_custom_target(echo_target_raw
   BYPRODUCTS echo_target_raw_$<CONFIG>.txt
   COMMENT echo_target_raw
similarity index 77%
rename from Tests/RunCMake/NinjaMultiConfig/Qt5.cmake
rename to Tests/RunCMake/NinjaMultiConfig/QtX.cmake
index 578256a..130f883 100644 (file)
@@ -1,18 +1,21 @@
 enable_language(CXX)
 
-find_package(Qt5Core REQUIRED)
+set(QtX Qt${with_qt_version})
+
+find_package(${QtX} REQUIRED COMPONENTS Core)
 
 set(CMAKE_AUTOMOC ON)
 set(CMAKE_AUTOMOC_COMPILER_PREDEFINES OFF)
 
+# Source files are always named qt5.* for simplicity but apply to Qt5 and later
 add_executable(exe qt5.cxx)
-target_link_libraries(exe PRIVATE Qt5::Core)
+target_link_libraries(exe PRIVATE ${QtX}::Core)
 
 include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
 generate_output_files(exe)
 
 set(moc_writes_depfiles 0)
-if(Qt5Core_VERSION VERSION_GREATER_EQUAL "5.15.0")
+if(${QtX}Core_VERSION VERSION_GREATER_EQUAL "5.15.0")
   set(moc_writes_depfiles 1)
 endif()
 
index 7c100eb..4a0c130 100644 (file)
@@ -344,6 +344,16 @@ run_ninja(CustomCommandOutputGenex echo_dbgx-release build-Release.ninja echo_db
 run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
 run_ninja(CustomCommandOutputGenex echo_dbgx-debug-in-release-graph build-Release.ninja echo_dbgx:Debug)
 run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# echo_depend_target
+run_ninja(CustomCommandOutputGenex echo_depend_target-debug-prep build-Debug.ninja echo:Debug)
+run_ninja(CustomCommandOutputGenex echo_depend_target-debug build-Debug.ninja echo_depend_target)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex echo_depend_target-release-prep build-Release.ninja echo:Release)
+run_ninja(CustomCommandOutputGenex echo_depend_target-release build-Release.ninja echo_depend_target)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+run_ninja(CustomCommandOutputGenex echo_depend_target-debug-in-release-graph-prep build-Release.ninja echo:Release)
+run_ninja(CustomCommandOutputGenex echo_depend_target-debug-in-release-graph build-Release.ninja echo_depend_target:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
 # echo_target_raw
 run_ninja(CustomCommandOutputGenex echo_target_raw-debug build-Debug.ninja echo_target_raw:Debug)
 run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
@@ -446,14 +456,20 @@ if(CMake_TEST_CUDA AND NOT CMake_TEST_CUDA STREQUAL "Clang")
   run_ninja(CudaSimple all-clean build-Debug.ninja clean:Debug)
 endif()
 
-if(CMake_TEST_Qt5)
-  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Qt5-build)
-  set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=all" "-DQt5Core_DIR=${Qt5Core_DIR}")
-  run_cmake_configure(Qt5)
+if(CMake_TEST_Qt_version)
+  set(QtX Qt${CMake_TEST_Qt_version})
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/QtX-build)
+  set(RunCMake_TEST_OPTIONS
+    "-DCMAKE_CROSS_CONFIGS=all"
+    "-Dwith_qt_version:STRING=${CMake_TEST_Qt_version}"
+    "-D${QtX}Core_DIR=${${QtX}Core_DIR}"
+    "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
+  )
+  run_cmake_configure(QtX)
   unset(RunCMake_TEST_OPTIONS)
   include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
-  run_cmake_build(Qt5 debug-in-release-graph Release exe:Debug)
-  if(CMAKE_TEST_Qt5Core_Version VERSION_GREATER_EQUAL 5.15.0)
-    run_ninja(Qt5 automoc-check build-Debug.ninja -t query exe_autogen/timestamp)
+  run_cmake_build(QtX debug-in-release-graph Release exe:Debug)
+  if(CMake_TEST_${QtX}Core_Version VERSION_GREATER_EQUAL 5.15.0)
+    run_ninja(QtX automoc-check build-Debug.ninja -t query exe_autogen/timestamp)
   endif()
 endif()
diff --git a/Tests/RunCMake/PrecompileHeaders/PchIncludedAllLanguages.cmake b/Tests/RunCMake/PrecompileHeaders/PchIncludedAllLanguages.cmake
new file mode 100644 (file)
index 0000000..a455410
--- /dev/null
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.15)
+project(PchIncludedAllLanguages C CXX)
+
+if(CMAKE_CXX_COMPILE_OPTIONS_USE_PCH)
+  add_definitions(-DHAVE_PCH_SUPPORT)
+endif()
+
+add_executable(main
+  main.cpp
+  pch-included.c
+  pch-included.cpp
+)
+target_precompile_headers(main PRIVATE pch.h)
+
+enable_testing()
+add_test(NAME main COMMAND main)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchLibObjLibExe.cmake b/Tests/RunCMake/PrecompileHeaders/PchLibObjLibExe.cmake
new file mode 100644 (file)
index 0000000..b4fdb71
--- /dev/null
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 3.16)
+project(PchLibObjLibExe CXX)
+
+foreach(i 1 2 3)
+    file(WRITE ${CMAKE_BINARY_DIR}/empty${i}.cpp "void nothing${i}() {}\n")
+endforeach()
+
+add_library(base_lib_static STATIC ${CMAKE_BINARY_DIR}/empty1.cpp)
+target_precompile_headers(base_lib_static PRIVATE <vector>)
+
+add_library(object_lib OBJECT ${CMAKE_BINARY_DIR}/empty2.cpp)
+target_precompile_headers(object_lib REUSE_FROM base_lib_static)
+
+add_library(mid_lib_static STATIC ${CMAKE_BINARY_DIR}/empty3.cpp)
+target_link_libraries(mid_lib_static PRIVATE object_lib)
+
+add_executable(exec main.cpp)
+target_link_libraries(exec PRIVATE mid_lib_static)
+set_target_properties(exec PROPERTIES MSVC_RUNTIME_LIBRARY MultiThreaded$<$<CONFIG:Debug>:Debug>)
+
+target_precompile_headers(exec PRIVATE <string>)
+
+enable_testing()
+add_test(NAME exec COMMAND exec)
index 8cc59d2..ca5b52e 100644 (file)
@@ -28,3 +28,5 @@ if(RunCMake_GENERATOR MATCHES "Make|Ninja")
   endif()
 endif()
 run_test(PchReuseFromObjLib)
+run_test(PchIncludedAllLanguages)
+run_test(PchLibObjLibExe)
diff --git a/Tests/RunCMake/PrecompileHeaders/pch-included.c b/Tests/RunCMake/PrecompileHeaders/pch-included.c
new file mode 100644 (file)
index 0000000..96fce69
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef HAVE_PCH_SUPPORT
+#  include "pch.h"
+#endif
+
+int testC(void)
+{
+  return PCH_INCLUDED;
+}
diff --git a/Tests/RunCMake/PrecompileHeaders/pch-included.cpp b/Tests/RunCMake/PrecompileHeaders/pch-included.cpp
new file mode 100644 (file)
index 0000000..bf4d95d
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef HAVE_PCH_SUPPORT
+#  include "pch.h"
+#endif
+
+int testCpp()
+{
+  return PCH_INCLUDED;
+}
index 81b6d9e..20672d1 100644 (file)
@@ -1,3 +1,5 @@
 #pragma once
 
 #define PCH_INCLUDED 1
+
+int testC(void);
index 02e0dec..3363a57 100644 (file)
@@ -156,9 +156,8 @@ function(run_cmake test)
 
     "|[^\n]*install_name_tool: warning: changes being made to the file will invalidate the code signature in:"
     "|[^\n]*xcodebuild[^\n]*DVTPlugInManager"
-    "|[^\n]*xcodebuild[^\n]*Requested but did not find extension point with identifier"
     "|[^\n]*xcodebuild[^\n]*warning: file type[^\n]*is based on missing file type"
-    "|[^\n]*objc[^\n]*: Class [^\n]* One of the two will be used. Which one is undefined."
+    "|[^\n]*objc[^\n]*: Class AMSupportURL[^\n]* One of the two will be used. Which one is undefined."
     "|[^\n]*is a member of multiple groups"
     "|[^\n]*offset in archive not a multiple of 8"
     "|[^\n]*from Time Machine by path"
diff --git a/Tests/RunCMake/UseSWIG/CMP0086-OLD-stderr.txt b/Tests/RunCMake/UseSWIG/CMP0086-OLD-stderr.txt
new file mode 100644 (file)
index 0000000..fca7a73
--- /dev/null
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0086-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0086 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
index e11a24a..d5ed136 100644 (file)
@@ -41,7 +41,6 @@ run_cmake(VsDeployEnabled)
 run_cmake(VsSettings)
 run_cmake(VsSourceSettingsTool)
 run_cmake(VsPlatformToolset)
-run_cmake(VsControlFlowGuardLinkSetting)
 
 run_cmake(VsWinRTByDefault)
 
diff --git a/Tests/RunCMake/VS10Project/VsControlFlowGuardLinkSetting-check.cmake b/Tests/RunCMake/VS10Project/VsControlFlowGuardLinkSetting-check.cmake
deleted file mode 100644 (file)
index c13858b..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/ControlFlowGuardProject.vcxproj")
-if(NOT EXISTS "${vcProjectFile}")
-  set(RunCMake_TEST_FAILED "Project file ControlFlowGuardProject.vcxproj does not exist.")
-  return()
-endif()
-
-set(Is_in_link_section 0)
-set(HAS_ControlFlowGuardSetting 0)
-
-file(STRINGS "${vcProjectFile}" lines)
-foreach(line IN LISTS lines)
-  if(line MATCHES "^ *<LinkControlFlowGuard>([^<>]+)</LinkControlFlowGuard>")
-      set(RunCMake_TEST_FAILED "Project file ControlFlowGuardProject.vcxproj contains the invalid <LinkControlFlowGuard> link property.")
-      return()
-    break()
-  endif()
-  if(line MATCHES "^ *<Link>")
-    # The start of the link section of the vcxproj file
-    set(Is_in_link_section 1)
-    continue()
-  endif()
-  if(line MATCHES "^ *</Link>")
-    # The end of the link section of the vcxproj file
-    set(Is_in_link_section 0)
-    continue()
-  endif()
-  if(Is_in_link_section)
-    if(line MATCHES "^ *<AdditionalOptions>([^<>]+)</AdditionalOptions>")
-      if("${CMAKE_MATCH_1}" MATCHES ".*/guard:cf.*")
-        set(HAS_ControlFlowGuardSetting 1)
-        break()
-      endif()
-    endif()
-  endif()
-endforeach()
-
-if(NOT HAS_ControlFlowGuardSetting)
-  set(RunCMake_TEST_FAILED "Project file ControlFlowGuardProject.vcxproj does not have '/guard:cf' specified in the <AdditionalOptions> property.")
-  return()
-endif()
diff --git a/Tests/RunCMake/VS10Project/VsControlFlowGuardLinkSetting.cmake b/Tests/RunCMake/VS10Project/VsControlFlowGuardLinkSetting.cmake
deleted file mode 100644 (file)
index 31e69ac..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-enable_language(CXX)
-
-# Add the Control Flow Guard compiler and linker option
-add_compile_options("/guard:cf")
-string(APPEND CMAKE_SHARED_LINKER_FLAGS " /guard:cf")
-
-add_library(ControlFlowGuardProject SHARED foo.cpp)
index 95fc5ca..39415af 100644 (file)
@@ -1,3 +1,3 @@
-CMake Error: Bad parameter for VS_DPI_AWARE: Bar
 CMake Error: Bad parameter for VS_DPI_AWARE: Foo
+CMake Error: Bad parameter for VS_DPI_AWARE: Bar
 CMake Generate step failed.  Build files cannot be regenerated correctly.
index 0f8b26c..13cc8e2 100644 (file)
@@ -4,20 +4,29 @@ macro(ensure_props_set projectFile)
     return()
   endif()
 
-  set(SettingFound FALSE)
+  set(Setting1Found FALSE)
+  set(Setting2Found FALSE)
 
   file(STRINGS "${projectFile}" lines)
   foreach(line IN LISTS lines)
     if(line MATCHES "<SourceProperty1.*Debug.*>SourceProperty1Value</SourceProperty1>")
       message("SourceProperty1 setting found")
-      set(SettingFound TRUE)
+      set(Setting1Found TRUE)
+    endif()
+    if(line MATCHES "<SourceProperty2.*Debug.*>SourceProperty2Value</SourceProperty2>")
+      message("SourceProperty2 setting found")
+      set(Setting2Found TRUE)
     endif()
   endforeach()
 
-  if (NOT SettingFound)
+  if (NOT Setting1Found)
     set(RunCMake_TEST_FAILED "SourceProperty1 setting was not found")
     return()
   endif()
+  if (NOT Setting2Found)
+    set(RunCMake_TEST_FAILED "SourceProperty2 setting was not found")
+    return()
+  endif()
 endmacro()
 
 ensure_props_set("${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
index a4b321b..3a046f1 100644 (file)
@@ -3,3 +3,5 @@ enable_language(CXX)
 add_library(foo foo.cpp shader.hlsl)
 set_property(SOURCE shader.hlsl PROPERTY VS_SETTINGS
   "$<$<CONFIG:DEBUG>:SourceProperty1=SourceProperty1Value>")
+set_property(SOURCE foo.cpp PROPERTY VS_SETTINGS
+  "$<$<CONFIG:DEBUG>:SourceProperty2=SourceProperty2Value>")
index f4fe07f..54375d5 100644 (file)
@@ -1,7 +1,7 @@
 add_executable(app MACOSX_BUNDLE main.m)
 
 set_target_properties(app PROPERTIES
-  XCODE_EMBED_FRAMEWORKS "${EXTERNAL_FWK}"
+  XCODE_EMBED_FRAMEWORKS "${EXTERNAL_DEPENDENCY}"
   XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY OFF
   XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY OFF
 )
index e4ea55d..23fd49d 100644 (file)
@@ -1,3 +1,3 @@
-if(NOT EXISTS ${RunCMake_TEST_BINARY_DIR}/Debug/app.app/Contents/Frameworks/sharedFrameworkExt.framework)
-  set(RunCMake_TEST_FAILED "Framework was not embedded at the expected location")
+if(NOT EXISTS ${RunCMake_TEST_BINARY_DIR}/Debug/app.app/Contents/Frameworks/${EXTERNAL_DEPENDENCY_NAME})
+  set(RunCMake_TEST_FAILED "${EXTERNAL_DEPENDENCY_NAME} was not embedded at the expected location")
 endif()
index 79d8d77..c76226f 100644 (file)
@@ -1,7 +1,7 @@
 add_executable(app MACOSX_BUNDLE main.m)
 
 set_target_properties(app PROPERTIES
-  XCODE_EMBED_FRAMEWORKS "${EXTERNAL_FWK}"
+  XCODE_EMBED_FRAMEWORKS "${EXTERNAL_DEPENDENCY}"
   XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY ON
   XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY ON
 )
index 57c79ea..732f04c 100644 (file)
@@ -1,3 +1,3 @@
-if(NOT EXISTS ${RunCMake_TEST_BINARY_DIR}/Debug/app.app/Contents/Frameworks/subdir/sharedFrameworkExt.framework)
-  set(RunCMake_TEST_FAILED "Framework was not embedded at the expected location")
+if(NOT EXISTS ${RunCMake_TEST_BINARY_DIR}/Debug/app.app/Contents/Frameworks/subdir/${EXTERNAL_DEPENDENCY_NAME})
+  set(RunCMake_TEST_FAILED "${EXTERNAL_DEPENDENCY_NAME} was not embedded at the expected location")
 endif()
index 4c78199..f83b1bf 100644 (file)
@@ -1,7 +1,7 @@
 add_executable(app MACOSX_BUNDLE main.m)
 
 set_target_properties(app PROPERTIES
-  XCODE_EMBED_FRAMEWORKS "${EXTERNAL_FWK}"
+  XCODE_EMBED_FRAMEWORKS "${EXTERNAL_DEPENDENCY}"
   XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY ON
   XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY ON
   XCODE_EMBED_FRAMEWORKS_PATH "subdir"
@@ -1,2 +1,4 @@
 add_library(sharedFrameworkExt SHARED func.m)
 set_target_properties(sharedFrameworkExt PROPERTIES FRAMEWORK TRUE)
+
+add_library(sharedDylibExt SHARED func.m)
index e94d084..f3a6918 100644 (file)
@@ -1,47 +1,49 @@
 include(RunCMake)
 
-# Build a framework that the other tests will use and treat as external.
+# Build dependencies that the other tests will use and treat as external.
 # Always build in the Debug configuration so that the path to the framework
 # is predictable.
-function(ExternalFramework)
+function(ExternalDependencies)
   set(RunCMake_TEST_NO_CLEAN 1)
-  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExternalFramework-build)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExternalDependencies-build)
   set(externalFramework ${RunCMake_TEST_BINARY_DIR}/Debug/sharedFrameworkExt.framework PARENT_SCOPE)
+  set(externalDylib ${RunCMake_TEST_BINARY_DIR}/Debug/libsharedDylibExt.dylib PARENT_SCOPE)
 
   file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
   file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
 
-  run_cmake(ExternalFramework)
-  run_cmake_command(ExternalFramework-build
+  run_cmake(ExternalDependencies)
+  run_cmake_command(ExternalDependencies-build
     ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR}
                      --config Debug
-                     --target sharedFrameworkExt
+                     --target sharedFrameworkExt sharedDylibExt
   )
 endfunction()
-ExternalFramework()
+ExternalDependencies()
 
-set(RunCMake_TEST_OPTIONS -DEXTERNAL_FWK=${externalFramework})
-
-run_cmake(EmbedFrameworksFlagsOff)
-
-function(TestFlagsOn testName)
+function(TestFlagsOn testName dependencyName)
   set(RunCMake_TEST_NO_CLEAN 1)
-  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${testName}-build)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${testName}-${dependencyName}-build)
 
   file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
   file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
 
   run_cmake(${testName})
-  run_cmake_command(${testName}-build
+  run_cmake_command(${testName}-${dependencyName}-build
     ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR}
                      --config Debug
                      --target app
   )
 endfunction()
 
-TestFlagsOn(EmbedFrameworksFlagsOnNoSubdir)
-TestFlagsOn(EmbedFrameworksFlagsOnWithSubdir)
-
+foreach(dependency ${externalFramework} ${externalDylib})
+  cmake_path(GET dependency FILENAME dependencyName)
+  set(RunCMake_TEST_OPTIONS -DEXTERNAL_DEPENDENCY=${dependency} -DEXTERNAL_DEPENDENCY_NAME=${dependencyName})
+  run_cmake(EmbedFrameworksFlagsOff)
+  TestFlagsOn(EmbedFrameworksFlagsOnNoSubdir ${dependencyName})
+  TestFlagsOn(EmbedFrameworksFlagsOnWithSubdir ${dependencyName})
+endforeach()
+unset(RunCMake_TEST_OPTIONS)
 
 function(TestAppExtension platform)
   set(testName EmbedAppExtensions-${platform})
diff --git a/Tests/RunCMake/add_subdirectory/CMP0082-OLD-stderr.txt b/Tests/RunCMake/add_subdirectory/CMP0082-OLD-stderr.txt
new file mode 100644 (file)
index 0000000..50838c3
--- /dev/null
@@ -0,0 +1,8 @@
+^CMake Deprecation Warning at CMakeLists.txt:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0082 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.$
diff --git a/Tests/RunCMake/cmake_host_system_information/000-FirstFallbackScript.cmake b/Tests/RunCMake/cmake_host_system_information/000-FirstFallbackScript.cmake
new file mode 100644 (file)
index 0000000..ad873eb
--- /dev/null
@@ -0,0 +1 @@
+message(WARNING "The warning text to match just to make sure the script get executed")
diff --git a/Tests/RunCMake/cmake_host_system_information/999-LastFallbackScript.cmake b/Tests/RunCMake/cmake_host_system_information/999-LastFallbackScript.cmake
new file mode 100644 (file)
index 0000000..08d8da8
--- /dev/null
@@ -0,0 +1,21 @@
+if(DEFINED CMAKE_GET_OS_RELEASE_FALLBACK_RESULT)
+  message(FATAL_ERROR "The `CMAKE_GET_OS_RELEASE_FALLBACK_RESULT` expected to be unset at this moment")
+endif()
+
+set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_NAME UnitTest)
+set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_PRETTY_NAME "Just a Unit Test")
+set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID unittest)
+set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID_LIKE nothing)
+set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION 0.0.1)
+set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION_ID 0.0.1)
+
+list(
+    APPEND CMAKE_GET_OS_RELEASE_FALLBACK_RESULT
+    CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_NAME
+    CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_PRETTY_NAME
+    IGNORED_VARIABLE_NAME_WHICH_IS_NOT_STARTED_WITH_EXPECTED_PREFIX
+    CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID
+    CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID_LIKE
+    CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION
+    CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION_ID
+  )
diff --git a/Tests/RunCMake/cmake_host_system_information/BadArg1-result.txt b/Tests/RunCMake/cmake_host_system_information/BadArg1-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_host_system_information/BadArg1-stderr.txt b/Tests/RunCMake/cmake_host_system_information/BadArg1-stderr.txt
new file mode 100644 (file)
index 0000000..ed995e6
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at BadArg1\.cmake:1 \(cmake_host_system_information\):
+  cmake_host_system_information missing RESULT specification.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:7 \(include\)
diff --git a/Tests/RunCMake/cmake_host_system_information/BadArg2-result.txt b/Tests/RunCMake/cmake_host_system_information/BadArg2-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_host_system_information/BadArg2-stderr.txt b/Tests/RunCMake/cmake_host_system_information/BadArg2-stderr.txt
new file mode 100644 (file)
index 0000000..b78c927
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at BadArg2\.cmake:1 \(cmake_host_system_information\):
+  cmake_host_system_information missing QUERY specification
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:7 \(include\)
diff --git a/Tests/RunCMake/cmake_host_system_information/BadArg3-result.txt b/Tests/RunCMake/cmake_host_system_information/BadArg3-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_host_system_information/BadArg3-stderr.txt b/Tests/RunCMake/cmake_host_system_information/BadArg3-stderr.txt
new file mode 100644 (file)
index 0000000..c3f1314
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at BadArg3\.cmake:1 \(cmake_host_system_information\):
+  cmake_host_system_information does not recognize <key> FOOBAR
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:7 \(include\)
diff --git a/Tests/RunCMake/cmake_host_system_information/CMakeLists.txt b/Tests/RunCMake/cmake_host_system_information/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0198f9b
--- /dev/null
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.21)
+
+project(${RunCMake_TEST} NONE)
+
+set(CMAKE_SYSROOT ${PROJECT_SOURCE_DIR}/${RunCMake_TEST})
+
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/cmake_host_system_information/CentOS6-stdout.txt b/Tests/RunCMake/cmake_host_system_information/CentOS6-stdout.txt
new file mode 100644 (file)
index 0000000..50dbb08
--- /dev/null
@@ -0,0 +1,7 @@
+-- CENTOS6_ID=`centos`
+-- CENTOS6_ID_LIKE=`rhel`
+-- CENTOS6_NAME=`CentOS`
+-- CENTOS6_PRETTY_NAME=`CentOS release 6\.10 \(Final\)`
+-- CENTOS6_USED_FALLBACK_SCRIPT=`.*/Modules/Internal/OSRelease/010-TryOldCentOS.cmake`
+-- CENTOS6_VERSION=`6\.10`
+-- CENTOS6_VERSION_ID=`6\.10`
diff --git a/Tests/RunCMake/cmake_host_system_information/CentOS6.cmake b/Tests/RunCMake/cmake_host_system_information/CentOS6.cmake
new file mode 100644 (file)
index 0000000..3bc632b
--- /dev/null
@@ -0,0 +1,5 @@
+cmake_host_system_information(RESULT CENTOS6 QUERY DISTRIB_INFO)
+
+foreach(VAR IN LISTS CENTOS6)
+  message(STATUS "${VAR}=`${${VAR}}`")
+endforeach()
diff --git a/Tests/RunCMake/cmake_host_system_information/CentOS6/etc/centos-release b/Tests/RunCMake/cmake_host_system_information/CentOS6/etc/centos-release
new file mode 100644 (file)
index 0000000..294ccc9
--- /dev/null
@@ -0,0 +1 @@
+CentOS release 6.10 (Final)
diff --git a/Tests/RunCMake/cmake_host_system_information/Debian6-stdout.txt b/Tests/RunCMake/cmake_host_system_information/Debian6-stdout.txt
new file mode 100644 (file)
index 0000000..4193d6f
--- /dev/null
@@ -0,0 +1,5 @@
+-- DEBIAN6_ID=`debian`
+-- DEBIAN6_NAME=`Debian`
+-- DEBIAN6_USED_FALLBACK_SCRIPT=`.*/Modules/Internal/OSRelease/020-TryDebianVersion.cmake`
+-- DEBIAN6_VERSION=`6\.0\.10`
+-- DEBIAN6_VERSION_ID=`6\.0\.10`
diff --git a/Tests/RunCMake/cmake_host_system_information/Debian6.cmake b/Tests/RunCMake/cmake_host_system_information/Debian6.cmake
new file mode 100644 (file)
index 0000000..cbf83a9
--- /dev/null
@@ -0,0 +1,5 @@
+cmake_host_system_information(RESULT DEBIAN6 QUERY DISTRIB_INFO)
+
+foreach(VAR IN LISTS DEBIAN6)
+  message(STATUS "${VAR}=`${${VAR}}`")
+endforeach()
diff --git a/Tests/RunCMake/cmake_host_system_information/Debian6/etc/debian_version b/Tests/RunCMake/cmake_host_system_information/Debian6/etc/debian_version
new file mode 100644 (file)
index 0000000..c7d48f0
--- /dev/null
@@ -0,0 +1 @@
+6.0.10
diff --git a/Tests/RunCMake/cmake_host_system_information/Exherbo-stdout.txt b/Tests/RunCMake/cmake_host_system_information/Exherbo-stdout.txt
new file mode 100644 (file)
index 0000000..11ae71f
--- /dev/null
@@ -0,0 +1,9 @@
+-- TEST1_ANSI_COLOR=`0;32`
+-- TEST1_BUG_REPORT_URL=`https://bugs.exherbo.org/`
+-- TEST1_HOME_URL=`https://www.exherbo.org/`
+-- TEST1_ID=`exherbo`
+-- TEST1_NAME=`Exherbo`
+-- TEST1_PRETTY_NAME=`Exherbo Linux`
+-- TEST1_SUPPORT_URL=`irc://irc.freenode.net/#exherbo`
+-- TEST2_ID=`exherbo`
+-- TEST2_VERSION=``
diff --git a/Tests/RunCMake/cmake_host_system_information/Exherbo.cmake b/Tests/RunCMake/cmake_host_system_information/Exherbo.cmake
new file mode 100644 (file)
index 0000000..7fc26d8
--- /dev/null
@@ -0,0 +1,11 @@
+cmake_host_system_information(RESULT TEST1 QUERY DISTRIB_INFO)
+
+foreach(VAR IN LISTS TEST1)
+  message(STATUS "${VAR}=`${${VAR}}`")
+endforeach()
+
+# Query individual variables
+cmake_host_system_information(RESULT TEST2 QUERY DISTRIB_ID DISTRIB_VERSION)
+list(POP_FRONT TEST2 TEST2_ID TEST2_VERSION)
+message(STATUS "TEST2_ID=`${TEST2_ID}`")
+message(STATUS "TEST2_VERSION=`${TEST2_VERSION}`")
diff --git a/Tests/RunCMake/cmake_host_system_information/Exherbo/etc/os-release b/Tests/RunCMake/cmake_host_system_information/Exherbo/etc/os-release
new file mode 100644 (file)
index 0000000..944c9b4
--- /dev/null
@@ -0,0 +1,7 @@
+NAME="Exherbo"
+PRETTY_NAME="Exherbo Linux"
+ID="exherbo"
+ANSI_COLOR="0;32"
+HOME_URL="https://www.exherbo.org/"
+SUPPORT_URL="irc://irc.freenode.net/#exherbo"
+BUG_REPORT_URL="https://bugs.exherbo.org/"
diff --git a/Tests/RunCMake/cmake_host_system_information/QueryKeys-stdout.txt b/Tests/RunCMake/cmake_host_system_information/QueryKeys-stdout.txt
new file mode 100644 (file)
index 0000000..f583deb
--- /dev/null
@@ -0,0 +1,27 @@
+-- NUMBER_OF_LOGICAL_CORES=`[0-9]+`
+-- NUMBER_OF_PHYSICAL_CORES=`[0-9]+`
+-- HOSTNAME=`.*`
+-- FQDN=`.*`
+-- TOTAL_VIRTUAL_MEMORY=`[0-9]+`
+-- AVAILABLE_VIRTUAL_MEMORY=`[0-9]+`
+-- TOTAL_PHYSICAL_MEMORY=`[0-9]+`
+-- AVAILABLE_PHYSICAL_MEMORY=`[0-9]+`
+-- IS_64BIT=`[01]`
+-- HAS_FPU=`[01]`
+-- HAS_MMX=`[01]`
+-- HAS_MMX_PLUS=`[01]`
+-- HAS_SSE=`[01]`
+-- HAS_SSE2=`[01]`
+-- HAS_SSE_FP=`[01]`
+-- HAS_SSE_MMX=`[01]`
+-- HAS_AMD_3DNOW=`[01]`
+-- HAS_AMD_3DNOW_PLUS=`[01]`
+-- HAS_IA64=`[01]`
+-- HAS_SERIAL_NUMBER=`[01]`
+-- PROCESSOR_SERIAL_NUMBER=`.*`
+-- PROCESSOR_NAME=`.*`
+-- PROCESSOR_DESCRIPTION=`.*`
+-- OS_NAME=`.*`
+-- OS_RELEASE=`.*`
+-- OS_VERSION=`.*`
+-- OS_PLATFORM=`.*`
@@ -1,19 +1,8 @@
-set(BadArg1-RESULT 1)
-set(BadArg1-STDERR "missing RESULT specification")
-set(BadArg2-RESULT 1)
-set(BadArg2-STDERR "missing QUERY specification")
-set(BadArg3-RESULT 1)
-set(BadArg3-STDERR "does not recognize <key> FOOBAR")
-set(QueryList-RESULT 0)
-set(QueryList-STDERR "\\[[0-9]+;[0-9]+\\]")
-
 function(try_and_print key)
-       cmake_host_system_information(RESULT RESULT QUERY ${key})
-       message(STATUS "[${key}] [${RESULT}]")
+  cmake_host_system_information(RESULT RESULT QUERY ${key})
+  message(STATUS "${key}=`${RESULT}`")
 endfunction()
 
-message("CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
-
 try_and_print(NUMBER_OF_LOGICAL_CORES)
 try_and_print(NUMBER_OF_PHYSICAL_CORES)
 try_and_print(HOSTNAME)
@@ -41,12 +30,3 @@ try_and_print(OS_NAME)
 try_and_print(OS_RELEASE)
 try_and_print(OS_VERSION)
 try_and_print(OS_PLATFORM)
-
-include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake")
-
-check_cmake_test(CMakeHostSystemInformation
-       BadArg1
-       BadArg2
-       BadArg3
-       QueryList
-)
diff --git a/Tests/RunCMake/cmake_host_system_information/QueryList-stdout.txt b/Tests/RunCMake/cmake_host_system_information/QueryList-stdout.txt
new file mode 100644 (file)
index 0000000..eebe0d4
--- /dev/null
@@ -0,0 +1 @@
+-- \[[0-9]+;[0-9]+\]
@@ -2,4 +2,4 @@ cmake_host_system_information(RESULT RESULT
   QUERY NUMBER_OF_LOGICAL_CORES NUMBER_OF_PHYSICAL_CORES
 )
 
-message("[${RESULT}]")
+message(STATUS "[${RESULT}]")
diff --git a/Tests/RunCMake/cmake_host_system_information/RunCMakeTest.cmake b/Tests/RunCMake/cmake_host_system_information/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..87b6944
--- /dev/null
@@ -0,0 +1,23 @@
+include(RunCMake)
+
+run_cmake(BadArg1)
+run_cmake(BadArg2)
+run_cmake(BadArg3)
+
+run_cmake(QueryList)
+run_cmake(QueryKeys)
+
+run_cmake(UnitTest)
+run_cmake(Exherbo)
+run_cmake(Ubuntu)
+
+run_cmake(CentOS6)
+run_cmake(Debian6)
+
+run_cmake(UserFallbackScript)
+
+if(RunCMake_GENERATOR MATCHES "^Visual Studio " AND NOT RunCMake_GENERATOR STREQUAL "Visual Studio 9 2008")
+  run_cmake(VsMSBuild)
+else()
+  run_cmake(VsMSBuildMissing)
+endif()
diff --git a/Tests/RunCMake/cmake_host_system_information/Ubuntu-stdout.txt b/Tests/RunCMake/cmake_host_system_information/Ubuntu-stdout.txt
new file mode 100644 (file)
index 0000000..d1a18da
--- /dev/null
@@ -0,0 +1,14 @@
+-- TEST1_BUG_REPORT_URL=`https://bugs\.launchpad\.net/ubuntu/`
+-- TEST1_HOME_URL=`https://www\.ubuntu\.com/`
+-- TEST1_ID=`ubuntu`
+-- TEST1_ID_LIKE=`debian`
+-- TEST1_NAME=`Ubuntu`
+-- TEST1_PRETTY_NAME=`Ubuntu 20\.04\.2 LTS`
+-- TEST1_PRIVACY_POLICY_URL=`https://www\.ubuntu\.com/legal/terms-and-policies/privacy-policy`
+-- TEST1_SUPPORT_URL=`https://help\.ubuntu\.com/`
+-- TEST1_UBUNTU_CODENAME=`focal`
+-- TEST1_VERSION=`20\.04\.2 LTS \(Focal Fossa\)`
+-- TEST1_VERSION_CODENAME=`focal`
+-- TEST1_VERSION_ID=`20\.04`
+-- TEST2_ID=`ubuntu`
+-- TEST2_VERSION=`20\.04\.2 LTS \(Focal Fossa\)`
diff --git a/Tests/RunCMake/cmake_host_system_information/Ubuntu.cmake b/Tests/RunCMake/cmake_host_system_information/Ubuntu.cmake
new file mode 100644 (file)
index 0000000..7fc26d8
--- /dev/null
@@ -0,0 +1,11 @@
+cmake_host_system_information(RESULT TEST1 QUERY DISTRIB_INFO)
+
+foreach(VAR IN LISTS TEST1)
+  message(STATUS "${VAR}=`${${VAR}}`")
+endforeach()
+
+# Query individual variables
+cmake_host_system_information(RESULT TEST2 QUERY DISTRIB_ID DISTRIB_VERSION)
+list(POP_FRONT TEST2 TEST2_ID TEST2_VERSION)
+message(STATUS "TEST2_ID=`${TEST2_ID}`")
+message(STATUS "TEST2_VERSION=`${TEST2_VERSION}`")
diff --git a/Tests/RunCMake/cmake_host_system_information/Ubuntu/etc/os-release b/Tests/RunCMake/cmake_host_system_information/Ubuntu/etc/os-release
new file mode 100644 (file)
index 0000000..f228f22
--- /dev/null
@@ -0,0 +1,12 @@
+NAME="Ubuntu"
+VERSION="20.04.2 LTS (Focal Fossa)"
+ID=ubuntu
+ID_LIKE=debian
+PRETTY_NAME="Ubuntu 20.04.2 LTS"
+VERSION_ID="20.04"
+HOME_URL="https://www.ubuntu.com/"
+SUPPORT_URL="https://help.ubuntu.com/"
+BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
+PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
+VERSION_CODENAME=focal
+UBUNTU_CODENAME=focal
diff --git a/Tests/RunCMake/cmake_host_system_information/UnitTest-stdout.txt b/Tests/RunCMake/cmake_host_system_information/UnitTest-stdout.txt
new file mode 100644 (file)
index 0000000..db6f487
--- /dev/null
@@ -0,0 +1,7 @@
+-- UNIT_TEST_A_LIST_LIKE_VARIABLE=`satu;dua;tiga`
+-- UNIT_TEST_DBL_QUOTED_VALUE=`"The" value in double "quotes"`
+-- UNIT_TEST_DBL_QUOTED_VALUE_STIPPED_COMMENT=`Blah blah blah`
+-- UNIT_TEST_NON_SPACE_VALUE=`Blah-blah-blah`
+-- UNIT_TEST_QUOTED_VALUE=`'The' value in single 'quotes'`
+-- UNIT_TEST_QUOTED_VALUE_STIPPED_COMMENT=`The value in single quotes`
+-- UNIT_TEST_THE_URL_WITH_ANCHOR_TEST=`https://blah.blah/resource#anchor`
diff --git a/Tests/RunCMake/cmake_host_system_information/UnitTest.cmake b/Tests/RunCMake/cmake_host_system_information/UnitTest.cmake
new file mode 100644 (file)
index 0000000..d9a0aca
--- /dev/null
@@ -0,0 +1,5 @@
+cmake_host_system_information(RESULT UNIT_TEST QUERY DISTRIB_INFO)
+
+foreach(VAR IN LISTS UNIT_TEST)
+  message(STATUS "${VAR}=`${${VAR}}`")
+endforeach()
diff --git a/Tests/RunCMake/cmake_host_system_information/UnitTest/etc/os-release b/Tests/RunCMake/cmake_host_system_information/UnitTest/etc/os-release
new file mode 100644 (file)
index 0000000..66c33b5
--- /dev/null
@@ -0,0 +1,9 @@
+# Comment string gonna be ignored
+NON_SPACE_VALUE=Blah-blah-blah
+QUOTED_VALUE='\'The\' value in single \'quotes\''
+QUOTED_VALUE_STIPPED_COMMENT='The value in single quotes'# The comment right after `'`
+DBL_QUOTED_VALUE="\"The\" value in double \"quotes\""
+DBL_QUOTED_VALUE_STIPPED_COMMENT="Blah blah blah"# The comment right after `'`
+THE_URL_WITH_ANCHOR_TEST="https://blah.blah/resource#anchor" # And a comment after
+A_LIST_LIKE_VARIABLE='satu;dua;tiga'
+INCORRECT_ESCAPE_IGNORED=\'This line gonna be ignored'
diff --git a/Tests/RunCMake/cmake_host_system_information/UserFallbackScript-stderr.txt b/Tests/RunCMake/cmake_host_system_information/UserFallbackScript-stderr.txt
new file mode 100644 (file)
index 0000000..78acea2
--- /dev/null
@@ -0,0 +1,5 @@
+CMake Warning at 000-FirstFallbackScript\.cmake:[0-9]+ \(message\):
+  The warning text to match just to make sure the script get executed
+Call Stack \(most recent call first\):
+  UserFallbackScript\.cmake:[0-9]+ \(cmake_host_system_information\)
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/cmake_host_system_information/UserFallbackScript-stdout.txt b/Tests/RunCMake/cmake_host_system_information/UserFallbackScript-stdout.txt
new file mode 100644 (file)
index 0000000..acaf47e
--- /dev/null
@@ -0,0 +1,7 @@
+-- UFS_ID=`unittest`
+-- UFS_ID_LIKE=`nothing`
+-- UFS_NAME=`UnitTest`
+-- UFS_PRETTY_NAME=`Just a Unit Test`
+-- UFS_USED_FALLBACK_SCRIPT=`.*/999-LastFallbackScript\.cmake`
+-- UFS_VERSION=`0\.0\.1`
+-- UFS_VERSION_ID=`0\.0\.1`
diff --git a/Tests/RunCMake/cmake_host_system_information/UserFallbackScript.cmake b/Tests/RunCMake/cmake_host_system_information/UserFallbackScript.cmake
new file mode 100644 (file)
index 0000000..660aa1c
--- /dev/null
@@ -0,0 +1,12 @@
+list(
+    APPEND CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTS
+    ${CMAKE_CURRENT_SOURCE_DIR}/000-FirstFallbackScript.cmake
+    ${CMAKE_CURRENT_SOURCE_DIR}/Ignored-Script.cmake
+    ${CMAKE_CURRENT_SOURCE_DIR}/999-LastFallbackScript.cmake
+  )
+
+cmake_host_system_information(RESULT UFS QUERY DISTRIB_INFO)
+
+foreach(VAR IN LISTS UFS)
+  message(STATUS "${VAR}=`${${VAR}}`")
+endforeach()
diff --git a/Tests/RunCMake/cmake_host_system_information/VsMSBuild.cmake b/Tests/RunCMake/cmake_host_system_information/VsMSBuild.cmake
new file mode 100644 (file)
index 0000000..30e616e
--- /dev/null
@@ -0,0 +1,4 @@
+cmake_host_system_information(RESULT msbuild QUERY VS_MSBUILD_COMMAND)
+if(NOT EXISTS "${msbuild}")
+  message(FATAL_ERROR "VS_MSBUILD_COMMAND returned path that does not exist:\n ${msbuild}")
+endif()
diff --git a/Tests/RunCMake/cmake_host_system_information/VsMSBuildMissing-result.txt b/Tests/RunCMake/cmake_host_system_information/VsMSBuildMissing-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_host_system_information/VsMSBuildMissing-stderr.txt b/Tests/RunCMake/cmake_host_system_information/VsMSBuildMissing-stderr.txt
new file mode 100644 (file)
index 0000000..3a7dfef
--- /dev/null
@@ -0,0 +1,4 @@
+^CMake Error at VsMSBuildMissing.cmake:[0-9]+ \(cmake_host_system_information\):
+  cmake_host_system_information does not recognize <key> VS_MSBUILD_COMMAND
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/cmake_host_system_information/VsMSBuildMissing.cmake b/Tests/RunCMake/cmake_host_system_information/VsMSBuildMissing.cmake
new file mode 100644 (file)
index 0000000..23c0364
--- /dev/null
@@ -0,0 +1 @@
+cmake_host_system_information(RESULT msbuild QUERY VS_MSBUILD_COMMAND)
diff --git a/Tests/RunCMake/ctest_environment/CMakeLists.txt.in b/Tests/RunCMake/ctest_environment/CMakeLists.txt.in
new file mode 100644 (file)
index 0000000..c9c4a64
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.21.0)
+project("@CASE_NAME@" NONE)
+include("@CASE_SOURCE_DIR@/@CASE_NAME@.cmake")
diff --git a/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-invalid-op-result.txt b/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-invalid-op-result.txt
new file mode 100644 (file)
index 0000000..b57e2de
--- /dev/null
@@ -0,0 +1 @@
+(-1|255)
diff --git a/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-invalid-op-stderr.txt b/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-invalid-op-stderr.txt
new file mode 100644 (file)
index 0000000..5b56d6f
--- /dev/null
@@ -0,0 +1 @@
+Error: Unrecognized environment manipulation argument: unknown
diff --git a/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-invalid-op.cmake b/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-invalid-op.cmake
new file mode 100644 (file)
index 0000000..d6ca4b2
--- /dev/null
@@ -0,0 +1,6 @@
+include(CTest)
+add_test(NAME cmake_version COMMAND "${CMAKE_COMMAND}" --version)
+
+set_property(TEST cmake_version
+  PROPERTY ENVIRONMENT_MODIFICATION
+    INVALID_OP=unknown:)
diff --git a/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-colon-result.txt b/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-colon-result.txt
new file mode 100644 (file)
index 0000000..b57e2de
--- /dev/null
@@ -0,0 +1 @@
+(-1|255)
diff --git a/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-colon-stderr.txt b/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-colon-stderr.txt
new file mode 100644 (file)
index 0000000..3ba6ba7
--- /dev/null
@@ -0,0 +1 @@
+Error: Missing `:` after the operation in: MISSING_COLON=unset
diff --git a/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-colon.cmake b/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-colon.cmake
new file mode 100644 (file)
index 0000000..601dd8b
--- /dev/null
@@ -0,0 +1,6 @@
+include(CTest)
+
+add_test(NAME cmake_version COMMAND "${CMAKE_COMMAND}" --version)
+set_property(TEST cmake_version
+  PROPERTY ENVIRONMENT_MODIFICATION
+    MISSING_COLON=unset)
diff --git a/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-equals-result.txt b/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-equals-result.txt
new file mode 100644 (file)
index 0000000..b57e2de
--- /dev/null
@@ -0,0 +1 @@
+(-1|255)
diff --git a/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-equals-stderr.txt b/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-equals-stderr.txt
new file mode 100644 (file)
index 0000000..20bc9a5
--- /dev/null
@@ -0,0 +1 @@
+Error: Missing `=` after the variable name in: MISSING_EQUAL
diff --git a/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-equals.cmake b/Tests/RunCMake/ctest_environment/ENVIRONMENT_MODIFICATION-no-equals.cmake
new file mode 100644 (file)
index 0000000..18448cf
--- /dev/null
@@ -0,0 +1,6 @@
+include(CTest)
+
+add_test(NAME cmake_version COMMAND "${CMAKE_COMMAND}" --version)
+set_property(TEST cmake_version
+  PROPERTY ENVIRONMENT_MODIFICATION
+    MISSING_EQUAL)
diff --git a/Tests/RunCMake/ctest_environment/RunCMakeTest.cmake b/Tests/RunCMake/ctest_environment/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..3447779
--- /dev/null
@@ -0,0 +1,12 @@
+include(RunCTest)
+
+# Isolate our ctest runs from external environment.
+unset(ENV{CTEST_PARALLEL_LEVEL})
+unset(ENV{CTEST_OUTPUT_ON_FAILURE})
+
+set(CASE_SOURCE_DIR "${RunCMake_SOURCE_DIR}")
+set(RunCTest_VERBOSE_FLAG "-VV")
+
+run_ctest(ENVIRONMENT_MODIFICATION-invalid-op)
+run_ctest(ENVIRONMENT_MODIFICATION-no-colon)
+run_ctest(ENVIRONMENT_MODIFICATION-no-equals)
diff --git a/Tests/RunCMake/ctest_environment/test.cmake.in b/Tests/RunCMake/ctest_environment/test.cmake.in
new file mode 100644 (file)
index 0000000..ca23c83
--- /dev/null
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.7)
+
+set(CTEST_SITE                          "test-site")
+set(CTEST_BUILD_NAME                    "test-build-name")
+set(CTEST_SOURCE_DIRECTORY              "@RunCMake_BINARY_DIR@/@CASE_NAME@")
+set(CTEST_BINARY_DIRECTORY              "@RunCMake_BINARY_DIR@/@CASE_NAME@-build")
+set(CTEST_CMAKE_GENERATOR               "@RunCMake_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM      "@RunCMake_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET       "@RunCMake_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION           "$ENV{CMAKE_CONFIG_TYPE}")
+
+set(ctest_test_args "@CASE_CTEST_TEST_ARGS@")
+ctest_start(Experimental)
+ctest_configure()
+ctest_build()
+ctest_test(${ctest_test_args})
diff --git a/Tests/RunCMake/ctest_memcheck/ExpectedOutputs-check.cmake b/Tests/RunCMake/ctest_memcheck/ExpectedOutputs-check.cmake
new file mode 100644 (file)
index 0000000..9d2a059
--- /dev/null
@@ -0,0 +1,10 @@
+function (find_xml_file name)
+  file(GLOB test_xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/${name}.xml")
+  if (NOT test_xml_file)
+    message(FATAL_ERROR
+      "${name}.xml not created.")
+  endif ()
+endfunction ()
+
+find_xml_file(DynamicAnalysis)
+find_xml_file(DynamicAnalysis-Test)
diff --git a/Tests/RunCMake/ctest_memcheck/ExpectedOutputs-stderr.txt b/Tests/RunCMake/ctest_memcheck/ExpectedOutputs-stderr.txt
new file mode 100644 (file)
index 0000000..e1fc77a
--- /dev/null
@@ -0,0 +1 @@
+Cannot find memory tester output file: .*/Tests/RunCMake/ctest_memcheck/ExpectedOutputs-build/Testing/Temporary/MemoryChecker.1.log\.\*
diff --git a/Tests/RunCMake/ctest_memcheck/ExpectedOutputs-stdout.txt b/Tests/RunCMake/ctest_memcheck/ExpectedOutputs-stdout.txt
new file mode 100644 (file)
index 0000000..b3473bf
--- /dev/null
@@ -0,0 +1,2 @@
+Memory checking results:
+left shift of negative value -256 - 1
index 6e0a91c..cb8f696 100644 (file)
@@ -95,6 +95,19 @@ unset(CMAKELISTS_EXTRA_CODE)
 unset(CTEST_EXTRA_CODE)
 
 #-----------------------------------------------------------------------------
+# add output test
+set(CTEST_EXTRA_CODE
+"set(CTEST_MEMORYCHECK_SANITIZER_OPTIONS \"simulate_sanitizer=1\")
+")
+set(CMAKELISTS_EXTRA_CODE
+"add_test(NAME TestSan COMMAND \"\${CMAKE_COMMAND}\"
+-P \"${RunCMake_SOURCE_DIR}/testUndefinedBehaviorSanitizer.cmake\")
+")
+run_mc_test(ExpectedOutputs "" -DMEMCHECK_TYPE=UndefinedBehaviorSanitizer)
+unset(CMAKELISTS_EXTRA_CODE)
+unset(CTEST_EXTRA_CODE)
+
+#-----------------------------------------------------------------------------
 set(CTEST_EXTRA_CODE "string(REPLACE \" \" \"\\\\ \" PRE_POST_COMMAND \"\${CTEST_MEMORYCHECK_COMMAND}\")
 
 set(CTEST_CUSTOM_PRE_MEMCHECK \"\${PRE_POST_COMMAND} pre command\")
index 5f9b32d..de81049 100644 (file)
@@ -158,13 +158,25 @@ add_test(
   COMMAND ${CMAKE_COMMAND} -E
   echo <DartMeasurement type="numeric/double" name="my_custom_value">1.4847</DartMeasurement>)
 add_test(
+  NAME double_measurement2
+  COMMAND ${CMAKE_COMMAND} -E
+  echo <CTestMeasurement type="numeric/double" name="another_custom_value">1.8474</CTestMeasurement>)
+add_test(
   NAME img_measurement
   COMMAND ${CMAKE_COMMAND} -E
   echo <DartMeasurementFile name="TestImage" type="image/png">]] ${IMAGE_DIR}/cmake-logo-16.png [[</DartMeasurementFile>)
 add_test(
+  NAME img_measurement2
+  COMMAND ${CMAKE_COMMAND} -E
+  echo <CTestMeasurementFile name="TestImage2" type="image/png">]] ${IMAGE_DIR}/cmake-logo-16.png [[</CTestMeasurementFile>)
+add_test(
   NAME file_measurement
   COMMAND ${CMAKE_COMMAND} -E
   echo <DartMeasurementFile name="my_test_input_data" type="file">]] ${IMAGE_DIR}/cmake-logo-16.png [[</DartMeasurementFile>)
+add_test(
+  NAME file_measurement2
+  COMMAND ${CMAKE_COMMAND} -E
+  echo <CTestMeasurementFile name="another_test_input_data" type="file">]] ${IMAGE_DIR}/cmake-logo-16.png [[</CTestMeasurementFile>)
   ]])
   run_ctest(TestMeasurements)
 endfunction()
@@ -194,3 +206,16 @@ set_property(TEST b PROPERTY LABELS b)
   run_ctest(TestChangingLabels)
 endfunction()
 run_changing_labels()
+
+# Verify that test output can add additional labels
+function(run_extra_labels)
+  set(CASE_CMAKELISTS_SUFFIX_CODE [[
+add_test(
+  NAME custom_labels
+  COMMAND ${CMAKE_COMMAND} -E
+  echo before\n<CTestLabel>label2</CTestLabel>\n<CTestLabel>label1</CTestLabel>\n<CTestLabel>label3</CTestLabel>\n<CTestLabel>label2</CTestLabel>\nafter)
+set_tests_properties(custom_labels PROPERTIES LABELS "label1")
+  ]])
+  run_ctest(TestExtraLabels)
+endfunction()
+run_extra_labels()
diff --git a/Tests/RunCMake/ctest_test/TestExtraLabels-check.cmake b/Tests/RunCMake/ctest_test/TestExtraLabels-check.cmake
new file mode 100644 (file)
index 0000000..eaa50d1
--- /dev/null
@@ -0,0 +1,25 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/Testing/TAG" _tag)
+string(REGEX REPLACE "^([^\n]*)\n.*$" "\\1" _date "${_tag}")
+file(READ "${RunCMake_TEST_BINARY_DIR}/Testing/${_date}/Test.xml" _test_contents)
+
+# Check labels.
+STRING(REGEX MATCHALL [[<Label>label1</Label>]] matches "${_test_contents}")
+list(LENGTH matches n_matches)
+if(NOT n_matches EQUAL 1)
+  string(APPEND RunCMake_TEST_FAILED  "expected 1 match for label1, found ${n_matches}")
+endif()
+STRING(REGEX MATCHALL [[<Label>label2</Label>]] matches "${_test_contents}")
+list(LENGTH matches n_matches)
+if(NOT n_matches EQUAL 1)
+  string(APPEND RunCMake_TEST_FAILED  "expected 1 match for label2, found ${n_matches}")
+endif()
+STRING(REGEX MATCHALL [[<Label>label3</Label>]] matches "${_test_contents}")
+list(LENGTH matches n_matches)
+if(NOT n_matches EQUAL 1)
+  string(APPEND RunCMake_TEST_FAILED  "expected 1 match for label3, found ${n_matches}")
+endif()
+
+# Check test output.
+if(NOT _test_contents MATCHES "<Value>before\nafter\n</Value>")
+  string(APPEND RunCMake_TEST_FAILED "Could not find expected output in Test.xml")
+endif()
index 0095db0..7e0928d 100644 (file)
@@ -10,13 +10,31 @@ endif()
 if(NOT _test_contents MATCHES "<Value>1.4847</Value>")
   string(APPEND RunCMake_TEST_FAILED "Could not find expected measurement value in Test.xml")
 endif()
+# Check the other double measurement.
+if(NOT _test_contents MATCHES [[NamedMeasurement type="numeric/double" name="another_custom_value"]])
+  string(APPEND RunCMake_TEST_FAILED
+    "Could not find expected <NamedMeasurement> tag(2) for type='numeric/double' in Test.xml")
+endif()
+if(NOT _test_contents MATCHES "<Value>1.8474</Value>")
+  string(APPEND RunCMake_TEST_FAILED "Could not find expected measurement value(2) in Test.xml")
+endif()
 # Check img measurement.
 if(NOT _test_contents MATCHES [[NamedMeasurement name="TestImage" type="image/png" encoding="base64"]])
   string(APPEND RunCMake_TEST_FAILED
     "Could not find expected <NamedMeasurement> tag for type='image/png' in Test.xml")
 endif()
+# Check img measurement 2.
+if(NOT _test_contents MATCHES [[NamedMeasurement name="TestImage2" type="image/png" encoding="base64"]])
+  string(APPEND RunCMake_TEST_FAILED
+    "Could not find expected <NamedMeasurement> tag(2) for type='image/png' in Test.xml")
+endif()
 # Check file measurement.
 if(NOT _test_contents MATCHES [[NamedMeasurement name="my_test_input_data" encoding="base64" compression="tar/gzip" filename="cmake-logo-16.png" type="file"]])
   string(APPEND RunCMake_TEST_FAILED
     "Could not find expected <NamedMeasurement> tag for type='file' in Test.xml")
 endif()
+# Check file measurement 2.
+if(NOT _test_contents MATCHES [[NamedMeasurement name="another_test_input_data" encoding="base64" compression="tar/gzip" filename="cmake-logo-16.png" type="file"]])
+  string(APPEND RunCMake_TEST_FAILED
+    "Could not find expected <NamedMeasurement> tag(2) for type='file' in Test.xml")
+endif()
index 5b86322..9ed1728 100644 (file)
@@ -1,2 +1,4 @@
 ^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
-  file Could not resolve file libtest\.so$
+  file Could not resolve runtime dependencies:
+
+    libtest\.so$
index eaca512..51010a1 100644 (file)
@@ -1,2 +1,4 @@
 ^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
-  file Could not resolve file libunresolved\.so$
+  file Could not resolve runtime dependencies:
+
+    libunresolved\.so$
index 01762b4..5743d27 100644 (file)
@@ -1,2 +1,4 @@
 ^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
-  file Could not resolve file @rpath/libunresolved\.dylib$
+  file Could not resolve runtime dependencies:
+
+    @rpath/libunresolved\.dylib$
index a20654c..0efcb57 100644 (file)
@@ -1,2 +1,4 @@
 ^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
-  file Could not resolve file (lib)?unresolved\.dll$
+  file Could not resolve runtime dependencies:
+
+    (lib)?unresolved\.dll$
index eb7b497..1ca2e75 100644 (file)
@@ -1,8 +1,6 @@
 include(RunCMake)
 
-if(HAVE_ELF_H)
-  run_cmake_command(ELF ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/ELF.cmake)
-endif()
+run_cmake_command(ELF ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/ELF.cmake)
 
 if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
   run_cmake_command(XCOFF ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/XCOFF.cmake)
index 9efd3f4..aff4735 100644 (file)
@@ -97,7 +97,9 @@ if(NOT WIN32
   run_cmake(READ_SYMLINK)
   run_cmake(READ_SYMLINK-noexist)
   run_cmake(READ_SYMLINK-notsymlink)
-  run_cmake(INSTALL-FOLLOW_SYMLINK_CHAIN)
+  if(NOT CYGWIN)
+    run_cmake(INSTALL-FOLLOW_SYMLINK_CHAIN)
+  endif()
 endif()
 
 run_cmake(REAL_PATH-unexpected-arg)
diff --git a/Tests/RunCMake/find_library/FromScriptMode-stderr-darwin.txt b/Tests/RunCMake/find_library/FromScriptMode-stderr-darwin.txt
new file mode 100644 (file)
index 0000000..185720b
--- /dev/null
@@ -0,0 +1,4 @@
+.*find_library considered the following locations.*
+.*\(lib\)library_no_exist\(\\.tbd\|\\.dylib\|\\.so\|\\.a\).*
+.*The item was found at.*
+.*lib/libcreated.a.*
diff --git a/Tests/RunCMake/find_library/FromScriptMode-stderr-windows.txt b/Tests/RunCMake/find_library/FromScriptMode-stderr-windows.txt
new file mode 100644 (file)
index 0000000..501ec0f
--- /dev/null
@@ -0,0 +1,4 @@
+.*find_library considered the following locations.*
+.*\(\|lib\)library_no_exist\(\\.lib\|\\.dll\\.a\|\\.a\).*
+.*The item was found at.*
+.*lib/libcreated.a.*
diff --git a/Tests/RunCMake/find_library/FromScriptMode-stderr.txt b/Tests/RunCMake/find_library/FromScriptMode-stderr.txt
new file mode 100644 (file)
index 0000000..046f680
--- /dev/null
@@ -0,0 +1,4 @@
+.*find_library considered the following locations.*
+.*\(lib\)library_no_exist\(\\.so\|\\.a\).*
+.*The item was found at.*
+.*lib/libcreated.a.*
diff --git a/Tests/RunCMake/find_library/FromScriptMode.cmake b/Tests/RunCMake/find_library/FromScriptMode.cmake
new file mode 100644 (file)
index 0000000..4d3c699
--- /dev/null
@@ -0,0 +1,15 @@
+
+if(TEMP_DIR)
+  file(REMOVE_RECURSE "${TEMP_DIR}")
+  file(MAKE_DIRECTORY "${TEMP_DIR}")
+  file(MAKE_DIRECTORY "${TEMP_DIR}/lib")
+  file(WRITE "${TEMP_DIR}/lib/libcreated.a" "created")
+endif()
+
+set(CMAKE_FIND_DEBUG_MODE 1)
+find_library(CREATED_LIBRARY NAMES library_no_exist)
+
+set(CMAKE_PREFIX_PATH "${TEMP_DIR}")
+find_library(CREATED_LIBRARY NAMES created)
+message(STATUS "CREATED_LIBRARY='${CREATED_LIBRARY}'")
+set(CMAKE_FIND_DEBUG_MODE 0)
index e297173..ad02c82 100644 (file)
@@ -10,3 +10,5 @@ endif()
 run_cmake(PrefixInPATH)
 run_cmake(Required)
 run_cmake(NO_CACHE)
+
+run_cmake_script(FromScriptMode "-DTEMP_DIR=${RunCMake_BINARY_DIR}/FromScriptMode-temp")
diff --git a/Tests/RunCMake/find_package/CMP0084-OLD-stderr.txt b/Tests/RunCMake/find_package/CMP0084-OLD-stderr.txt
new file mode 100644 (file)
index 0000000..0db83aa
--- /dev/null
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0084-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0084 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/find_package/MissingNormalForceRequired-result.txt b/Tests/RunCMake/find_package/MissingNormalForceRequired-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_package/MissingNormalForceRequired-stderr.txt b/Tests/RunCMake/find_package/MissingNormalForceRequired-stderr.txt
new file mode 100644 (file)
index 0000000..f6c0b44
--- /dev/null
@@ -0,0 +1,20 @@
+CMake Error at MissingNormalForceRequired.cmake:2 \(find_package\):
+  No "FindNotHere.cmake" found in CMAKE_MODULE_PATH\.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
++
+CMake Warning \(dev\) at MissingNormalForceRequired.cmake:2 \(find_package\):
+  FindNotHere.cmake must either be part of this project itself, in this case
+  adjust CMAKE_MODULE_PATH so that it points to the correct location inside
+  its source tree\.
+
+  Or it must be installed by a package which has already been found via
+  find_package\(\)\.  In this case make sure that package has indeed been found
+  and adjust CMAKE_MODULE_PATH to contain the location where that package has
+  installed FindNotHere\.cmake\.  This must be a location provided by that
+  package.  This error in general means that the buildsystem of this project
+  is relying on a Find-module without ensuring that it is actually available\.
+
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/find_package/MissingNormalForceRequired.cmake b/Tests/RunCMake/find_package/MissingNormalForceRequired.cmake
new file mode 100644 (file)
index 0000000..5935316
--- /dev/null
@@ -0,0 +1,3 @@
+set(CMAKE_REQUIRE_FIND_PACKAGE_NotHere ON)
+find_package(NotHere MODULE)
+message(FATAL_ERROR "This error must not be reachable.")
diff --git a/Tests/RunCMake/find_package/RequiredOptionValuesClash-result.txt b/Tests/RunCMake/find_package/RequiredOptionValuesClash-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_package/RequiredOptionValuesClash-stderr.txt b/Tests/RunCMake/find_package/RequiredOptionValuesClash-stderr.txt
new file mode 100644 (file)
index 0000000..b4fdd98
--- /dev/null
@@ -0,0 +1,11 @@
+CMake Error at RequiredOptionValuesClash.cmake:4 \(find_package\):
+  find_package for module Foo was made REQUIRED with
+  CMAKE_REQUIRE_FIND_PACKAGE_Foo but CMAKE_DISABLE_FIND_PACKAGE_Foo is
+  enabled.  A REQUIRED package cannot be disabled.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
++
+CMake Error at RequiredOptionValuesClash.cmake:5 \(message\):
+  This error must not be reachable\.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/find_package/RequiredOptionValuesClash.cmake b/Tests/RunCMake/find_package/RequiredOptionValuesClash.cmake
new file mode 100644 (file)
index 0000000..04fece7
--- /dev/null
@@ -0,0 +1,5 @@
+set(CMAKE_DISABLE_FIND_PACKAGE_Foo ON)
+set(CMAKE_REQUIRE_FIND_PACKAGE_Foo ON)
+
+find_package(Foo)
+message(FATAL_ERROR "This error must not be reachable.")
index 3ba04c8..b20a889 100644 (file)
@@ -6,6 +6,7 @@ run_cmake(ComponentRequiredAndOptional)
 run_cmake(FromPATHEnv)
 run_cmake(FromPrefixPath)
 run_cmake(MissingNormal)
+run_cmake(MissingNormalForceRequired)
 run_cmake(MissingNormalRequired)
 run_cmake(MissingNormalVersion)
 run_cmake(MissingNormalWarnNoModuleOld)
@@ -23,6 +24,7 @@ run_cmake(PackageRootNestedConfig)
 run_cmake(PackageRootNestedModule)
 run_cmake(PolicyPush)
 run_cmake(PolicyPop)
+run_cmake(RequiredOptionValuesClash)
 run_cmake(SetFoundFALSE)
 run_cmake(WrongVersion)
 run_cmake(WrongVersionConfig)
diff --git a/Tests/RunCMake/if/IncompleteMatches-stdout.txt b/Tests/RunCMake/if/IncompleteMatches-stdout.txt
new file mode 100644 (file)
index 0000000..634d988
--- /dev/null
@@ -0,0 +1,6 @@
+-- Test #1 passed
+-- Test #2 passed
+-- Test #3 passed
+-- Test #4 passed
+-- Test #5 passed
+-- Test #6 passed
diff --git a/Tests/RunCMake/if/IncompleteMatches.cmake b/Tests/RunCMake/if/IncompleteMatches.cmake
new file mode 100644 (file)
index 0000000..7142cfc
--- /dev/null
@@ -0,0 +1,36 @@
+if(MATCHES)
+  message(SEND_ERROR "Test #1 failed")
+else()
+  message(STATUS "Test #1 passed")
+endif()
+
+if("" MATCHES "")
+  message(STATUS "Test #2 passed")
+else()
+  message(SEND_ERROR "Test #2 failed")
+endif()
+
+if(MATCHES RHS)
+  message(SEND_ERROR "Test #3 failed")
+else()
+  message(STATUS "Test #3 passed")
+endif()
+
+set(RHS "")
+if(MATCHES RHS)
+  message(SEND_ERROR "Test #4 failed")
+else()
+  message(STATUS "Test #4 passed")
+endif()
+
+if(MATCHES "^$")
+  message(SEND_ERROR "Test #5 failed")
+else()
+  message(STATUS "Test #5 passed")
+endif()
+
+if("" MATCHES "^$")
+  message(STATUS "Test #6 passed")
+else()
+  message(SEND_ERROR "Test #6 failed")
+endif()
diff --git a/Tests/RunCMake/if/IncompleteMatchesFail-result.txt b/Tests/RunCMake/if/IncompleteMatchesFail-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/if/IncompleteMatchesFail-stderr.txt b/Tests/RunCMake/if/IncompleteMatchesFail-stderr.txt
new file mode 100644 (file)
index 0000000..6e8ac80
--- /dev/null
@@ -0,0 +1,6 @@
+CMake Error at IncompleteMatchesFail\.cmake:1 \(if\):
+  if given arguments:
+
+    "LHS" "MATCHES"
+
+  Unknown arguments specified
diff --git a/Tests/RunCMake/if/IncompleteMatchesFail.cmake b/Tests/RunCMake/if/IncompleteMatchesFail.cmake
new file mode 100644 (file)
index 0000000..a3ef2b8
--- /dev/null
@@ -0,0 +1,2 @@
+if(LHS MATCHES)
+endif()
index f54edf7..6baa840 100644 (file)
@@ -9,7 +9,11 @@ run_cmake(duplicate-else-after-elseif)
 run_cmake(elseif-message)
 run_cmake(misplaced-elseif)
 
+run_cmake(unbalanced-parenthesis)
+
 run_cmake(MatchesSelf)
+run_cmake(IncompleteMatches)
+run_cmake(IncompleteMatchesFail)
 
 run_cmake(TestNameThatExists)
 run_cmake(TestNameThatDoesNotExist)
diff --git a/Tests/RunCMake/if/unbalanced-parenthesis-result.txt b/Tests/RunCMake/if/unbalanced-parenthesis-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/if/unbalanced-parenthesis-stderr.txt b/Tests/RunCMake/if/unbalanced-parenthesis-stderr.txt
new file mode 100644 (file)
index 0000000..770ccb8
--- /dev/null
@@ -0,0 +1,8 @@
+CMake Error at unbalanced-parenthesis\.cmake:[0-9]+ \(if\):
+  if given arguments:
+
+    "NOT" "\(" "IN_LIST" "some_list"
+
+  mismatched parenthesis in condition
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/if/unbalanced-parenthesis.cmake b/Tests/RunCMake/if/unbalanced-parenthesis.cmake
new file mode 100644 (file)
index 0000000..c51c755
--- /dev/null
@@ -0,0 +1,8 @@
+set(var_with_paren "(")
+set(some_list "")
+
+if(NOT ${var_with_paren} IN_LIST some_list)
+  message(STATUS "Never prints")
+else()
+  message(STATUS "Never prints")
+endif()
diff --git a/Tests/RunCMake/install/CMP0087-OLD-stderr.txt b/Tests/RunCMake/install/CMP0087-OLD-stderr.txt
new file mode 100644 (file)
index 0000000..5233ebc
--- /dev/null
@@ -0,0 +1,8 @@
+^CMake Deprecation Warning at CMP0087-OLD/CMakeLists.txt:5 \(cmake_policy\):
+  The OLD behavior for policy CMP0087 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.$
index cd4dcb3..d54777b 100644 (file)
@@ -1 +1 @@
-RESULT=2005-08-07 23:19:49 Sunday=Sun August=Aug 05 day=219 wd=0 week=32 %I=11 epoch=1123456789
+RESULT=2005-08-07 23:19:49 Sunday=Sun August=Aug 05 day=219 wd=0 week=32 w_iso=31 %I=11 epoch=1123456789
index cba258d..7fd6d72 100644 (file)
@@ -1,3 +1,3 @@
 set(ENV{SOURCE_DATE_EPOCH} "1123456789")
-string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S %A=%a %B=%b %y day=%j wd=%w week=%U %%I=%I epoch=%s" UTC)
+string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S %A=%a %B=%b %y day=%j wd=%w week=%U w_iso=%V %%I=%I epoch=%s" UTC)
 message("RESULT=${RESULT}")
index 5b4761c..cf4c540 100644 (file)
@@ -1,4 +1,2 @@
-^CMake Error at cxx_not_enabled.cmake:[0-9]+ \(target_compile_features\):
-  target_compile_features cannot use features from non-enabled language CXX
-Call Stack \(most recent call first\):
-  CMakeLists\.txt:[0-9]+ \(include\)$
+^CMake Error:.*CMake can not determine linker language for target: main.*
+CMake Generate step failed.  Build files cannot be regenerated correctly.$
index 7da80ac..bb9b991 100644 (file)
@@ -5,3 +5,5 @@ run_cmake(EndMissing)
 run_cmake(EndMismatch)
 run_cmake(EndAlone)
 run_cmake(EndAloneArgs)
+
+run_cmake(unbalanced-parenthesis)
diff --git a/Tests/RunCMake/while/unbalanced-parenthesis-result.txt b/Tests/RunCMake/while/unbalanced-parenthesis-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/while/unbalanced-parenthesis-stderr.txt b/Tests/RunCMake/while/unbalanced-parenthesis-stderr.txt
new file mode 100644 (file)
index 0000000..9d4132c
--- /dev/null
@@ -0,0 +1,8 @@
+CMake Error at unbalanced-parenthesis.cmake:[0-9]+ \(while\):
+  had incorrect arguments:
+
+    "NOT" "\(" "IN_LIST" "some_list"
+
+  mismatched parenthesis in condition
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/while/unbalanced-parenthesis.cmake b/Tests/RunCMake/while/unbalanced-parenthesis.cmake
new file mode 100644 (file)
index 0000000..7a12701
--- /dev/null
@@ -0,0 +1,8 @@
+set(var_with_paren "(")
+set(some_list "")
+
+while(NOT ${var_with_paren} IN_LIST some_list)
+  message(STATUS "Never prints")
+endwhile()
+
+message(STATUS "Never prints")
index 6c0d5e4..c3f9e03 100644 (file)
@@ -67,7 +67,7 @@ add_test(NAME UseSWIG.BasicPerl COMMAND
   --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
 if(SWIG_FOUND AND NOT SWIG_VERSION VERSION_LESS "4.0.2"
-    AND CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode")
+    AND CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode|Visual Studio (1[1-9]|[2-9][0-9])")
   add_test(NAME UseSWIG.Depfile.BasicPython COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -76,7 +76,6 @@ if(SWIG_FOUND AND NOT SWIG_VERSION VERSION_LESS "4.0.2"
     ${build_generator_args}
     --build-project TestBasicPython
     --build-options ${build_options} -DSWIG_USE_SWIG_DEPENDENCIES=ON
-                                     "-DSWIG_OUTFILE_DIR=${CMake_BINARY_DIR}/Tests/UseSWIG/BasicPython.Depfile"
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
   add_test(NAME UseSWIG.Depfile.BasicPerl COMMAND
index 0ccb721..69b4e2f 100644 (file)
@@ -3,7 +3,7 @@
 
 if(NOT CMake_SOURCE_DIR)
   set(CMakeDeveloperReference_STANDALONE 1)
-  cmake_minimum_required(VERSION 3.1...3.19 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.1...3.20 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)
index f1bdcc4..8c55c85 100644 (file)
 
   # Wrappers for 3rd-party libraries
   { include: [ "@<.*curl/curlver.h>", private, "<cm3p/curl/curl.h>", public ] },
+  { include: [ "@<.*json/config.h>", private, "<cm3p/json/value.h>", public ] },
   { include: [ "@<.*json/forwards.h>", private, "<cm3p/json/value.h>", public ] },
   { include: [ "@<.*uv/.+\\.h>", private, "<cm3p/uv.h>", public ] },
   { include: [ "@<.*expat_external.h>", private, "<cm3p/expat.h>", public ] },
index b2e14d5..25a063a 100644 (file)
@@ -162,7 +162,11 @@ An includer may test the following macros after inclusion:
 #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
 # define KWIML_INT_HAVE_INTTYPES_H 1
 #elif defined(_MSC_VER) /* MSVC */
-# define KWIML_INT_NO_INTTYPES_H 1
+# if _MSC_VER >= 1800
+#  define KWIML_INT_HAVE_INTTYPES_H 1
+# else
+#  define KWIML_INT_NO_INTTYPES_H 1
+# endif
 #elif defined(__BORLANDC__) /* Borland */
 # define KWIML_INT_NO_INTTYPES_H 1
 #elif defined(__WATCOMC__) /* Watcom */
@@ -272,6 +276,15 @@ An includer may test the following macros after inclusion:
 # define KWIML_INT_BROKEN_PRIXPTR 1
 #endif
 
+#if defined(_MSC_VER) && _MSC_VER < 1900
+  /* MSVC scanf seems broken on 8-bit sizes until 19.00 */
+# define KWIML_INT_BROKEN_SCNd8 1
+# define KWIML_INT_BROKEN_SCNi8 1
+# define KWIML_INT_BROKEN_SCNo8 1
+# define KWIML_INT_BROKEN_SCNu8 1
+# define KWIML_INT_BROKEN_SCNx8 1
+#endif
+
 #if (defined(__SUNPRO_C)||defined(__SUNPRO_CC)) && defined(_CHAR_IS_UNSIGNED)
 # define KWIML_INT_BROKEN_INT8_T 1 /* system type defined incorrectly */
 #elif defined(__BORLANDC__) && defined(_CHAR_UNSIGNED)
@@ -303,7 +316,7 @@ An includer may test the following macros after inclusion:
 #elif defined(__BORLANDC__)
 # define KWIML_INT_private_NO_SCN8
 # define KWIML_INT_private_NO_SCN64
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) && _MSC_VER < 1900
 # define KWIML_INT_private_NO_SCN8
 #elif defined(__WATCOMC__)
 # define KWIML_INT_private_NO_SCN8
index d5a036a..a4f7445 100644 (file)
@@ -11,10 +11,8 @@ ARG FROM_IMAGE_NAME=kitware/cmake:build-win-x86-deps-2020-04-27
 ARG FROM_IMAGE_DIGEST=@sha256:04e229c0c0ba2247855d0e8c0fb87c1686f983adbafa4ce413e61b3905edb76b
 ARG FROM_IMAGE=$FROM_IMAGE_NAME$FROM_IMAGE_DIGEST
 
-FROM $FROM_IMAGE as source
+FROM $FROM_IMAGE as build
 COPY . C:\cmake\src\cmake
-
-FROM source as build
 ARG ARCH="x86_64"
 ARG TEST="true"
 RUN \cmake\src\cmake\Utilities\Release\win\x86\build.bat %ARCH% %TEST%
index 34ff4de..dd8e7a8 100755 (executable)
@@ -8,7 +8,7 @@ readonly name="curl"
 readonly ownership="Curl Upstream <curl-library@cool.haxx.se>"
 readonly subtree="Utilities/cmcurl"
 readonly repo="https://github.com/curl/curl.git"
-readonly tag="curl-7_77_0"
+readonly tag="curl-7_79_1"
 readonly shortlog=false
 readonly paths="
   CMake/*
diff --git a/Utilities/Scripts/update-elf.bash b/Utilities/Scripts/update-elf.bash
new file mode 100755 (executable)
index 0000000..1a065ba
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="elf"
+readonly ownership="FreeBSD Upstream <kwrobot@kitware.com>"
+readonly subtree="Utilities/cmelf"
+readonly repo="https://github.com/freebsd/freebsd-src.git"
+readonly tag="main"
+readonly shortlog=false
+readonly paths="
+  sys/sys/elf32.h
+  sys/sys/elf64.h
+  sys/sys/elf_common.h
+"
+
+extract_source () {
+    git_archive
+    pushd "${extractdir}/${name}-reduced"
+    echo "* -whitespace" > .gitattributes
+    mv sys/sys/* .
+    sed -i -e 's/<sys\/elf_common.h>/"elf_common.h"/g' -e 's/u_int32_t/uint32_t/g' *.h
+    popd
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
index f8fe544..5ed00e7 100755 (executable)
@@ -8,7 +8,7 @@ readonly name="jsoncpp"
 readonly ownership="JsonCpp Upstream <kwrobot@kitware.com>"
 readonly subtree="Utilities/cmjsoncpp"
 readonly repo="https://github.com/open-source-parsers/jsoncpp.git"
-readonly tag="1.8.2"
+readonly tag="1.9.4"
 readonly shortlog=false
 readonly paths="
   LICENSE
index 3db89ff..3a24e2b 100755 (executable)
@@ -8,7 +8,7 @@ readonly name="LibArchive"
 readonly ownership="LibArchive Upstream <libarchive-discuss@googlegroups.com>"
 readonly subtree="Utilities/cmlibarchive"
 readonly repo="https://github.com/libarchive/libarchive.git"
-readonly tag="v3.4.2"
+readonly tag="v3.5.1"
 readonly shortlog=false
 readonly paths="
   CMakeLists.txt
index 0d0a667..bfe6828 100644 (file)
 # For convenience, the function may use the "git_archive" function which
 # does a standard "git archive" extraction using the (optional) "paths"
 # variable to only extract a subset of the source tree.
+#
+# Dependencies
+#
+# To update third party packages from git repositories with submodule,
+# you will need to install the "git-archive-all" Python package with
+#
+#   pip install git-archive-all
+#
+# or install it from https://github.com/Kentzo/git-archive-all.
+#
+# This package installs a script named "git-archive-all" where pip
+# installs executables. If you run pip under your user privileges (i.e.,
+# not using "sudo"), this location may be $HOME/.local/bin. Make sure
+# that directory is in your path so that git can find the
+# "git-archive-all" script.
+#
 ########################################################################
 
 ########################################################################
@@ -52,11 +68,24 @@ git_archive () {
         tar -C "$extractdir" -x
 }
 
+confirm_archive_all_exists () {
+    which git-archive-all || die "git requires an archive-all command. Please run 'pip install git-archive-all'"
+}
+
+git_archive_all () {
+    confirm_archive_all_exists
+    local tmptarball="temp.tar"
+    git archive-all --prefix="" "$tmptarball"
+    mkdir -p "$extractdir/$name-reduced"
+    tar -C "$extractdir/$name-reduced" -xf "$tmptarball" $paths
+    rm -f "$tmptarball"
+}
+
 disable_custom_gitattributes() {
     pushd "${extractdir}/${name}-reduced"
     # Git does not allow custom attributes in a subdirectory where we
     # are about to merge the `.gitattributes` file, so disable them.
-    sed -i '/^\[attr\]/ {s/^/#/}' .gitattributes
+    sed -i '/^\[attr\]/ {s/^/#/;}' .gitattributes
     popd
 }
 
@@ -71,6 +100,9 @@ warn () {
 
 readonly regex_date='20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
 readonly basehash_regex="$name $regex_date ([0-9a-f]*)"
+readonly toplevel_dir="$( git rev-parse --show-toplevel )"
+
+cd "$toplevel_dir"
 
 ########################################################################
 # Sanity checking
@@ -95,7 +127,7 @@ if [ ! -d "$(git rev-parse --show-toplevel)/$subtree" ]; then
 else
     readonly basehash="$( git rev-list --author="$ownership" --grep="$basehash_regex" -n 1 HEAD )"
 fi
-readonly upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$basehash_regex"'/ {s/.*(//;s/)//;p}' | egrep '^[0-9a-f]+$' )"
+readonly upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$basehash_regex"'/ {s/.*(//;s/)//;p;}' | egrep '^[0-9a-f]+$' )"
 
 [ -n "$basehash" ] || \
     warn "'basehash' is empty; performing initial import"
@@ -111,7 +143,7 @@ readonly extractdir="$workdir/extract"
 trap "rm -rf '$workdir'" EXIT
 
 # Get upstream
-git clone "$repo" "$upstreamdir"
+git clone --recursive "$repo" "$upstreamdir"
 
 if [ -n "$basehash" ]; then
     # Remove old worktrees
@@ -120,7 +152,7 @@ if [ -n "$basehash" ]; then
     git worktree add "$extractdir" "$basehash"
     # Clear out the working tree
     pushd "$extractdir"
-    git ls-files | xargs rm -v
+    git ls-files -z --recurse-submodules | xargs -0 rm -v
     find . -type d -empty -delete
     popd
 else
@@ -132,6 +164,8 @@ fi
 # Extract the subset of upstream we care about
 pushd "$upstreamdir"
 git checkout "$tag"
+git submodule sync --recursive
+git submodule update --recursive --init
 readonly upstream_hash="$( git rev-parse HEAD )"
 readonly upstream_hash_short="$( git rev-parse --short=8 "$upstream_hash" )"
 readonly upstream_datetime="$( git rev-list "$upstream_hash" --format='%ci' -n 1 | grep -e "^$regex_date" )"
index a9b62f9..48ca5a1 100755 (executable)
@@ -8,7 +8,7 @@ readonly name="zstd"
 readonly ownership="zstd upstream <kwrobot@kitware.com>"
 readonly subtree="Utilities/cmzstd"
 readonly repo="https://github.com/facebook/zstd.git"
-readonly tag="v1.4.5"
+readonly tag="v1.5.0"
 readonly shortlog=false
 readonly paths="
   LICENSE
@@ -23,7 +23,7 @@ readonly paths="
   lib/deprecated/*.h
   lib/dictBuilder/*.c
   lib/dictBuilder/*.h
-  lib/zstd.h
+  lib/*.h
 "
 
 extract_source () {
index 32efd48..c8a970d 100644 (file)
@@ -3,7 +3,7 @@
 
 if(NOT CMake_SOURCE_DIR)
   set(CMakeHelp_STANDALONE 1)
-  cmake_minimum_required(VERSION 3.1...3.19 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.1...3.20 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)
@@ -58,6 +58,13 @@ configure_file(conf.py.in conf.py @ONLY)
 set(doc_formats "")
 if(SPHINX_HTML)
   list(APPEND doc_formats html)
+
+  # we provide the path to the produced html output in the console
+  # for tools that support URI protocol schemes
+  set(html_extra_commands
+    COMMAND ${CMAKE_COMMAND} -E echo "sphinx-build html: HTML documentation generated in file://${CMAKE_CURRENT_BINARY_DIR}/html/index.html"
+  )
+
 endif()
 if(SPHINX_MAN)
   list(APPEND doc_formats man)
index bab3046..7e38df9 100644 (file)
@@ -180,6 +180,7 @@ if(WIN32)
   set(HAVE_STRERROR_R 0)
   set(HAVE_STRNCMPI 0)
   set(HAVE_STRNCPY_S 1)
+  set(HAVE_STRNLEN 1)
   set(HAVE_STROPTS_H 0)
   set(HAVE__STRTOI64 1)
   set(HAVE_STRTOLL 1)
index 2fcce1b..e418146 100644 (file)
@@ -71,21 +71,15 @@ main ()
 }
 #endif
 
-/* tests for gethostbyaddr_r or gethostbyname_r */
-#if defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) || \
-    defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) || \
-    defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) || \
-    defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) || \
+/* tests for gethostbyname_r */
+#if defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) || \
     defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \
     defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
 #   define _REENTRANT
     /* no idea whether _REENTRANT is always set, just invent a new flag */
 #   define TEST_GETHOSTBYFOO_REENTRANT
 #endif
-#if defined(HAVE_GETHOSTBYADDR_R_5) || \
-    defined(HAVE_GETHOSTBYADDR_R_7) || \
-    defined(HAVE_GETHOSTBYADDR_R_8) || \
-    defined(HAVE_GETHOSTBYNAME_R_3) || \
+#if defined(HAVE_GETHOSTBYNAME_R_3) || \
     defined(HAVE_GETHOSTBYNAME_R_5) || \
     defined(HAVE_GETHOSTBYNAME_R_6) || \
     defined(TEST_GETHOSTBYFOO_REENTRANT)
@@ -98,18 +92,10 @@ int main(void)
   int type = 0;
   struct hostent h;
   int rc = 0;
-#if defined(HAVE_GETHOSTBYADDR_R_5) || \
-    defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) || \
-    \
-    defined(HAVE_GETHOSTBYNAME_R_3) || \
+#if defined(HAVE_GETHOSTBYNAME_R_3) || \
     defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT)
   struct hostent_data hdata;
-#elif defined(HAVE_GETHOSTBYADDR_R_7) || \
-      defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) || \
-      defined(HAVE_GETHOSTBYADDR_R_8) || \
-      defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) || \
-      \
-      defined(HAVE_GETHOSTBYNAME_R_5) || \
+#elif defined(HAVE_GETHOSTBYNAME_R_5) || \
       defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \
       defined(HAVE_GETHOSTBYNAME_R_6) || \
       defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
@@ -118,24 +104,6 @@ int main(void)
   struct hostent *hp;
 #endif
 
-#ifndef gethostbyaddr_r
-  (void)gethostbyaddr_r;
-#endif
-
-#if   defined(HAVE_GETHOSTBYADDR_R_5) || \
-      defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT)
-  rc = gethostbyaddr_r(address, length, type, &h, &hdata);
-  (void)rc;
-#elif defined(HAVE_GETHOSTBYADDR_R_7) || \
-      defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT)
-  hp = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &h_errnop);
-  (void)hp;
-#elif defined(HAVE_GETHOSTBYADDR_R_8) || \
-      defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT)
-  rc = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &hp, &h_errnop);
-  (void)rc;
-#endif
-
 #if   defined(HAVE_GETHOSTBYNAME_R_3) || \
       defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT)
   rc = gethostbyname_r(address, &h, &hdata);
@@ -214,37 +182,6 @@ if (sizeof (bool *) )
 #include <float.h>
 int main() { return 0; }
 #endif
-#ifdef HAVE_INET_NTOA_R_DECL
-#include <arpa/inet.h>
-
-typedef void (*func_type)();
-
-int main()
-{
-#ifndef inet_ntoa_r
-  func_type func;
-  func = (func_type)inet_ntoa_r;
-  (void)func;
-#endif
-  return 0;
-}
-#endif
-#ifdef HAVE_INET_NTOA_R_DECL_REENTRANT
-#define _REENTRANT
-#include <arpa/inet.h>
-
-typedef void (*func_type)();
-
-int main()
-{
-#ifndef inet_ntoa_r
-  func_type func;
-  func = (func_type)&inet_ntoa_r;
-  (void)func;
-#endif
-  return 0;
-}
-#endif
 #ifdef HAVE_GETADDRINFO
 #include <netdb.h>
 #include <sys/types.h>
@@ -361,7 +298,7 @@ main ()
 
 /* IoctlSocket source code */
         long flags = 0;
-        if(0 != ioctlsocket(0, FIONBIO, &flags))
+        if(0 != IoctlSocket(0, FIONBIO, &flags))
           return 1;
   ;
   return 0;
index bbd4632..7fda7ac 100644 (file)
@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+# Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
 #
 # This software is licensed as described in the file COPYING, which
 # you should have received as part of this distribution. The terms
@@ -54,6 +54,40 @@ if(1) # CMake hard-codes these
   set(RECV_TYPE_ARG4 "int")
   set(RECV_TYPE_RETV "ssize_t")
 else()
+function(curl_cv_func_recv_run_test recv_retv recv_arg1 recv_arg2 recv_arg3 recv_arg4)
+  unset(curl_cv_func_recv_test CACHE)
+  check_c_source_compiles("
+    ${_source_epilogue}
+    #ifdef WINSOCK_API_LINKAGE
+    WINSOCK_API_LINKAGE
+    #endif
+    extern ${recv_retv} ${signature_call_conv}
+    recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4});
+    int main(void) {
+      ${recv_arg1} s=0;
+      ${recv_arg2} buf=0;
+      ${recv_arg3} len=0;
+      ${recv_arg4} flags=0;
+      ${recv_retv} res = recv(s, buf, len, flags);
+      (void) res;
+      return 0;
+    }"
+    curl_cv_func_recv_test)
+  message(STATUS
+    "Tested: ${recv_retv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4})")
+  if(curl_cv_func_recv_test)
+    set(curl_cv_func_recv_args
+      "${recv_arg1},${recv_arg2},${recv_arg3},${recv_arg4},${recv_retv}" PARENT_SCOPE)
+    set(RECV_TYPE_ARG1 "${recv_arg1}" PARENT_SCOPE)
+    set(RECV_TYPE_ARG2 "${recv_arg2}" PARENT_SCOPE)
+    set(RECV_TYPE_ARG3 "${recv_arg3}" PARENT_SCOPE)
+    set(RECV_TYPE_ARG4 "${recv_arg4}" PARENT_SCOPE)
+    set(RECV_TYPE_RETV "${recv_retv}" PARENT_SCOPE)
+    set(HAVE_RECV 1 PARENT_SCOPE)
+    set(curl_cv_func_recv_done 1 PARENT_SCOPE)
+  endif()
+endfunction()
+
 check_c_source_compiles("${_source_epilogue}
 int main(void) {
     recv(0, 0, 0, 0);
@@ -61,43 +95,16 @@ int main(void) {
 }" curl_cv_recv)
 if(curl_cv_recv)
   if(NOT DEFINED curl_cv_func_recv_args OR curl_cv_func_recv_args STREQUAL "unknown")
+    if(APPLE)
+      curl_cv_func_recv_run_test("ssize_t" "int" "void *" "size_t" "int")
+    endif()
     foreach(recv_retv "int" "ssize_t" )
       foreach(recv_arg1 "SOCKET" "int" )
         foreach(recv_arg2 "char *" "void *" )
           foreach(recv_arg3 "int" "size_t" "socklen_t" "unsigned int")
             foreach(recv_arg4 "int" "unsigned int")
               if(NOT curl_cv_func_recv_done)
-                unset(curl_cv_func_recv_test CACHE)
-                check_c_source_compiles("
-                  ${_source_epilogue}
-                  #ifdef WINSOCK_API_LINKAGE
-                  WINSOCK_API_LINKAGE
-                  #endif
-                  extern ${recv_retv} ${signature_call_conv}
-                  recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4});
-                  int main(void) {
-                    ${recv_arg1} s=0;
-                    ${recv_arg2} buf=0;
-                    ${recv_arg3} len=0;
-                    ${recv_arg4} flags=0;
-                    ${recv_retv} res = recv(s, buf, len, flags);
-                    (void) res;
-                    return 0;
-                  }"
-                  curl_cv_func_recv_test)
-                message(STATUS
-                  "Tested: ${recv_retv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4})")
-                if(curl_cv_func_recv_test)
-                  set(curl_cv_func_recv_args
-                    "${recv_arg1},${recv_arg2},${recv_arg3},${recv_arg4},${recv_retv}")
-                  set(RECV_TYPE_ARG1 "${recv_arg1}")
-                  set(RECV_TYPE_ARG2 "${recv_arg2}")
-                  set(RECV_TYPE_ARG3 "${recv_arg3}")
-                  set(RECV_TYPE_ARG4 "${recv_arg4}")
-                  set(RECV_TYPE_RETV "${recv_retv}")
-                  set(HAVE_RECV 1)
-                  set(curl_cv_func_recv_done 1)
-                endif()
+                curl_cv_func_recv_run_test(${recv_retv} ${recv_arg1} ${recv_arg2} ${recv_arg3} ${recv_arg4})
               endif()
             endforeach()
           endforeach()
@@ -130,6 +137,42 @@ if(1) # CMake hard-codes these
   set(SEND_TYPE_ARG4 "int")
   set(SEND_TYPE_RETV "ssize_t")
 else()
+function(curl_cv_func_send_run_test send_retv send_arg1 send_arg2 send_arg3 send_arg4)
+  unset(curl_cv_func_send_test CACHE)
+  check_c_source_compiles("
+    ${_source_epilogue}
+    #ifdef WINSOCK_API_LINKAGE
+    WINSOCK_API_LINKAGE
+    #endif
+    extern ${send_retv} ${signature_call_conv}
+    send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4});
+    int main(void) {
+      ${send_arg1} s=0;
+      ${send_arg2} buf=0;
+      ${send_arg3} len=0;
+      ${send_arg4} flags=0;
+      ${send_retv} res = send(s, buf, len, flags);
+      (void) res;
+      return 0;
+    }"
+    curl_cv_func_send_test)
+  message(STATUS
+    "Tested: ${send_retv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4})")
+  if(curl_cv_func_send_test)
+    string(REGEX REPLACE "(const) .*" "\\1" send_qual_arg2 "${send_arg2}")
+    string(REGEX REPLACE "const (.*)" "\\1" send_arg2 "${send_arg2}")
+    set(curl_cv_func_send_args
+      "${send_arg1},${send_arg2},${send_arg3},${send_arg4},${send_retv},${send_qual_arg2}" PARENT_SCOPE)
+    set(SEND_TYPE_ARG1 "${send_arg1}" PARENT_SCOPE)
+    set(SEND_TYPE_ARG2 "${send_arg2}" PARENT_SCOPE)
+    set(SEND_TYPE_ARG3 "${send_arg3}" PARENT_SCOPE)
+    set(SEND_TYPE_ARG4 "${send_arg4}" PARENT_SCOPE)
+    set(SEND_TYPE_RETV "${send_retv}" PARENT_SCOPE)
+    set(HAVE_SEND 1 PARENT_SCOPE)
+    set(curl_cv_func_send_done 1 PARENT_SCOPE)
+  endif()
+endfunction()
+
 check_c_source_compiles("${_source_epilogue}
 int main(void) {
     send(0, 0, 0, 0);
@@ -137,45 +180,16 @@ int main(void) {
 }" curl_cv_send)
 if(curl_cv_send)
   if(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown")
+    if(APPLE)
+      curl_cv_func_send_run_test("ssize_t" "int" "const void *" "size_t" "int")
+    endif()
     foreach(send_retv "int" "ssize_t" )
       foreach(send_arg1 "SOCKET" "int" "ssize_t" )
         foreach(send_arg2 "const char *" "const void *" "void *" "char *")
           foreach(send_arg3 "int" "size_t" "socklen_t" "unsigned int")
             foreach(send_arg4 "int" "unsigned int")
               if(NOT curl_cv_func_send_done)
-                unset(curl_cv_func_send_test CACHE)
-                check_c_source_compiles("
-                  ${_source_epilogue}
-                  #ifdef WINSOCK_API_LINKAGE
-                  WINSOCK_API_LINKAGE
-                  #endif
-                  extern ${send_retv} ${signature_call_conv}
-                  send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4});
-                  int main(void) {
-                    ${send_arg1} s=0;
-                    ${send_arg2} buf=0;
-                    ${send_arg3} len=0;
-                    ${send_arg4} flags=0;
-                    ${send_retv} res = send(s, buf, len, flags);
-                    (void) res;
-                    return 0;
-                  }"
-                  curl_cv_func_send_test)
-                message(STATUS
-                  "Tested: ${send_retv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4})")
-                if(curl_cv_func_send_test)
-                  string(REGEX REPLACE "(const) .*" "\\1" send_qual_arg2 "${send_arg2}")
-                  string(REGEX REPLACE "const (.*)" "\\1" send_arg2 "${send_arg2}")
-                  set(curl_cv_func_send_args
-                    "${send_arg1},${send_arg2},${send_arg3},${send_arg4},${send_retv},${send_qual_arg2}")
-                  set(SEND_TYPE_ARG1 "${send_arg1}")
-                  set(SEND_TYPE_ARG2 "${send_arg2}")
-                  set(SEND_TYPE_ARG3 "${send_arg3}")
-                  set(SEND_TYPE_ARG4 "${send_arg4}")
-                  set(SEND_TYPE_RETV "${send_retv}")
-                  set(HAVE_SEND 1)
-                  set(curl_cv_func_send_done 1)
-                endif()
+                curl_cv_func_send_run_test("${send_retv}" "${send_arg1}" "${send_arg2}" "${send_arg3}" "${send_arg4}")
               endif()
             endforeach()
           endforeach()
@@ -223,28 +237,6 @@ int main(void) {
   return 0;
 }" HAVE_STRUCT_TIMEVAL)
 
-set(HAVE_SIG_ATOMIC_T 1)
-set(CMAKE_REQUIRED_FLAGS)
-if(HAVE_SIGNAL_H)
-  set(CMAKE_REQUIRED_FLAGS "-DHAVE_SIGNAL_H")
-  set(CMAKE_EXTRA_INCLUDE_FILES "signal.h")
-endif()
-check_type_size("sig_atomic_t" SIZEOF_SIG_ATOMIC_T)
-if(HAVE_SIZEOF_SIG_ATOMIC_T)
-  check_c_source_compiles("
-    #ifdef HAVE_SIGNAL_H
-    #  include <signal.h>
-    #endif
-    int main(void) {
-      static volatile sig_atomic_t dummy = 0;
-      (void)dummy;
-      return 0;
-    }" HAVE_SIG_ATOMIC_T_NOT_VOLATILE)
-  if(NOT HAVE_SIG_ATOMIC_T_NOT_VOLATILE)
-    set(HAVE_SIG_ATOMIC_T_VOLATILE 1)
-  endif()
-endif()
-
 if(HAVE_WINDOWS_H)
   set(CMAKE_EXTRA_INCLUDE_FILES winsock2.h)
 else()
@@ -262,6 +254,9 @@ endif()
 unset(CMAKE_TRY_COMPILE_TARGET_TYPE)
 
 if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
+  if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+  # only try this on non-macOS
+
   # if not cross-compilation...
   include(CheckCSourceRuns)
   set(CMAKE_REQUIRED_FLAGS "")
@@ -304,5 +299,6 @@ if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
         }
         return 0;
     }" HAVE_POLL_FINE)
+  endif()
 endif()
 
index c393557..dd653da 100644 (file)
@@ -46,7 +46,6 @@ if(NOT UNIX)
     set(HAVE_PROCESS_H 1)
     set(HAVE_PWD_H 0)
     set(HAVE_SETJMP_H 1)
-    set(HAVE_SGTTY_H 0)
     set(HAVE_SIGNAL_H 1)
     set(HAVE_SOCKIO_H 0)
     set(HAVE_STDINT_H 0)
@@ -81,12 +80,8 @@ if(NOT UNIX)
     set(HAVE_STRCASECMP 0)
     set(HAVE_STRICMP 1)
     set(HAVE_STRCMPI 1)
-    set(HAVE_GETHOSTBYADDR 1)
     set(HAVE_GETTIMEOFDAY 0)
     set(HAVE_INET_ADDR 1)
-    set(HAVE_INET_NTOA 1)
-    set(HAVE_INET_NTOA_R 0)
-    set(HAVE_PERROR 1)
     set(HAVE_CLOSESOCKET 1)
     set(HAVE_SETVBUF 0)
     set(HAVE_SIGSETJMP 0)
@@ -100,17 +95,10 @@ if(NOT UNIX)
     set(HAVE_RAND_STATUS 0)
     set(HAVE_GMTIME_R 0)
     set(HAVE_LOCALTIME_R 0)
-    set(HAVE_GETHOSTBYADDR_R 0)
     set(HAVE_GETHOSTBYNAME_R 0)
     set(HAVE_SIGNAL_FUNC 1)
     set(HAVE_SIGNAL_MACRO 0)
 
-    set(HAVE_GETHOSTBYADDR_R_5 0)
-    set(HAVE_GETHOSTBYADDR_R_5_REENTRANT 0)
-    set(HAVE_GETHOSTBYADDR_R_7 0)
-    set(HAVE_GETHOSTBYADDR_R_7_REENTRANT 0)
-    set(HAVE_GETHOSTBYADDR_R_8 0)
-    set(HAVE_GETHOSTBYADDR_R_8_REENTRANT 0)
     set(HAVE_GETHOSTBYNAME_R_3 0)
     set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)
     set(HAVE_GETHOSTBYNAME_R_5 0)
@@ -121,8 +109,6 @@ if(NOT UNIX)
     set(TIME_WITH_SYS_TIME 0)
     set(HAVE_O_NONBLOCK 0)
     set(HAVE_IN_ADDR_T 0)
-    set(HAVE_INET_NTOA_R_DECL 0)
-    set(HAVE_INET_NTOA_R_DECL_REENTRANT 0)
     if(ENABLE_IPV6)
       set(HAVE_GETADDRINFO 1)
     else()
index 16ef037..9eef01a 100644 (file)
@@ -12,20 +12,32 @@ set(CURL_DISABLE_ALTSVC ON)
 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_DOH OFF)
 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_GETOPTIONS OFF)
 set(CURL_DISABLE_GOPHER ON CACHE INTERNAL "Disable curl gopher protocol?")
 set(CURL_DISABLE_HSTS ON)
+set(CURL_DISABLE_HTTP_AUTH OFF)
 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_LIBCURL_OPTION OFF)
+set(CURL_DISABLE_MIME OFF)
 set(CURL_DISABLE_MQTT ON)
+set(CURL_DISABLE_NETRC OFF)
+set(CURL_DISABLE_NTLM OFF)
 set(CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG OFF)
+set(CURL_DISABLE_PARSEDATE OFF)
 set(CURL_DISABLE_POP3 ON CACHE INTERNAL "Disable curl pop3 protocol?")
+set(CURL_DISABLE_PROGRESS_METER OFF)
 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_SHUFFLE_DNS OFF)
+set(CURL_DISABLE_SMB OFF)
 set(CURL_DISABLE_SMTP ON CACHE INTERNAL "Disable curl smtp protocol?")
+set(CURL_DISABLE_SOCKETPAIR OFF)
 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")
@@ -272,43 +284,77 @@ if(0) # This code not needed for building within CMake.
 include(CurlSymbolHiding)
 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_ENABLE_EXPORT_TARGET "to enable cmake export target" ON)
+mark_as_advanced(CURL_ENABLE_EXPORT_TARGET)
+
+option(CURL_DISABLE_ALTSVC "disables alt-svc support" OFF)
+mark_as_advanced(CURL_DISABLE_ALTSVC)
+option(CURL_DISABLE_COOKIES "disables cookies support" OFF)
+mark_as_advanced(CURL_DISABLE_COOKIES)
+option(CURL_DISABLE_CRYPTO_AUTH "disables cryptographic authentication" OFF)
+mark_as_advanced(CURL_DISABLE_CRYPTO_AUTH)
 option(CURL_DISABLE_DICT "disables DICT" OFF)
 mark_as_advanced(CURL_DISABLE_DICT)
+option(CURL_DISABLE_DOH "disables DNS-over-HTTPS" OFF)
+mark_as_advanced(CURL_DISABLE_DOH)
 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_FTP "disables FTP" OFF)
+mark_as_advanced(CURL_DISABLE_FTP)
+option(CURL_DISABLE_GETOPTIONS "disables curl_easy_options API for existing options to curl_easy_setopt" OFF)
+mark_as_advanced(CURL_DISABLE_GETOPTIONS)
+option(CURL_DISABLE_GOPHER "disables Gopher" OFF)
+mark_as_advanced(CURL_DISABLE_GOPHER)
+option(CURL_DISABLE_HSTS "disables HSTS support" OFF)
+mark_as_advanced(CURL_DISABLE_HSTS)
 option(CURL_DISABLE_HTTP "disables HTTP" OFF)
 mark_as_advanced(CURL_DISABLE_HTTP)
-
-option(CURL_DISABLE_LDAPS "to disable LDAPS" OFF)
+option(CURL_DISABLE_HTTP_AUTH "disables all HTTP authentication methods" OFF)
+mark_as_advanced(CURL_DISABLE_HTTP_AUTH)
+option(CURL_DISABLE_IMAP "disables IMAP" OFF)
+mark_as_advanced(CURL_DISABLE_IMAP)
+option(CURL_DISABLE_LDAP "disables LDAP" OFF)
+mark_as_advanced(CURL_DISABLE_LDAP)
+option(CURL_DISABLE_LDAPS "disables 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)
+option(CURL_DISABLE_LIBCURL_OPTION "disables --libcurl option from the curl tool" OFF)
+mark_as_advanced(CURL_DISABLE_LIBCURL_OPTION)
+option(CURL_DISABLE_MIME "disables MIME support" OFF)
+mark_as_advanced(CURL_DISABLE_MIME)
+option(CURL_DISABLE_MQTT "disables MQTT" OFF)
+mark_as_advanced(CURL_DISABLE_MQTT)
+option(CURL_DISABLE_NETRC "disables netrc parser" OFF)
+mark_as_advanced(CURL_DISABLE_NETRC)
+option(CURL_DISABLE_NTLM "disables NTLM support" OFF)
+mark_as_advanced(CURL_DISABLE_NTLM)
+option(CURL_DISABLE_PARSEDATE "disables date parsing" OFF)
+mark_as_advanced(CURL_DISABLE_PARSEDATE)
+option(CURL_DISABLE_POP3 "disables 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)
+option(CURL_DISABLE_PROGRESS_METER "disables built-in progress meter" OFF)
+mark_as_advanced(CURL_DISABLE_PROGRESS_METER)
+option(CURL_DISABLE_PROXY "disables proxy support" OFF)
+mark_as_advanced(CURL_DISABLE_PROXY)
+option(CURL_DISABLE_RTSP "disables RTSP" OFF)
+mark_as_advanced(CURL_DISABLE_RTSP)
+option(CURL_DISABLE_SHUFFLE_DNS "disables shuffle DNS feature" OFF)
+mark_as_advanced(CURL_DISABLE_SHUFFLE_DNS)
+option(CURL_DISABLE_SMB "disables SMB" OFF)
+mark_as_advanced(CURL_DISABLE_SMB)
+option(CURL_DISABLE_SMTP "disables SMTP" OFF)
 mark_as_advanced(CURL_DISABLE_SMTP)
-option(CURL_DISABLE_GOPHER "to disable Gopher" OFF)
-mark_as_advanced(CURL_DISABLE_GOPHER)
-option(CURL_DISABLE_MQTT "to disable MQTT" OFF)
-mark_as_advanced(CURL_DISABLE_MQTT)
+option(CURL_DISABLE_SOCKETPAIR "disables use of socketpair for curl_multi_poll" OFF)
+mark_as_advanced(CURL_DISABLE_SOCKETPAIR)
+option(CURL_DISABLE_TELNET "disables Telnet" OFF)
+mark_as_advanced(CURL_DISABLE_TELNET)
+option(CURL_DISABLE_TFTP "disables TFTP" OFF)
+mark_as_advanced(CURL_DISABLE_TFTP)
+option(CURL_DISABLE_VERBOSE_STRINGS "disables verbose strings" OFF)
+mark_as_advanced(CURL_DISABLE_VERBOSE_STRINGS)
 
-option(CURL_ENABLE_EXPORT_TARGET "to enable cmake export target" ON)
-mark_as_advanced(CURL_ENABLE_EXPORT_TARGET)
+# Corresponds to HTTP_ONLY in lib/curl_setup.h
+option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" OFF)
+mark_as_advanced(HTTP_ONLY)
 
 if(HTTP_ONLY)
   set(CURL_DISABLE_DICT ON)
@@ -327,16 +373,6 @@ if(HTTP_ONLY)
   set(CURL_DISABLE_TFTP ON)
 endif()
 
-option(CURL_DISABLE_ALTSVC "to disable alt-svc support" OFF)
-mark_as_advanced(CURL_DISABLE_ALTSVC)
-option(CURL_DISABLE_HSTS "to disable HSTS support" OFF)
-mark_as_advanced(CURL_DISABLE_HSTS)
-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(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON)
 mark_as_advanced(ENABLE_IPV6)
 if(ENABLE_IPV6 AND NOT WIN32)
@@ -495,28 +531,29 @@ if(CMAKE_USE_DARWINSSL)
   message(FATAL_ERROR "The cmake option CMAKE_USE_DARWINSSL was renamed to CMAKE_USE_SECTRANSP.")
 endif()
 
-if(CMAKE_USE_SECTRANSP)
+if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
   find_library(COREFOUNDATION_FRAMEWORK "CoreFoundation")
   if(NOT COREFOUNDATION_FRAMEWORK)
       message(FATAL_ERROR "CoreFoundation framework not found")
   endif()
 
-  find_library(SECURITY_FRAMEWORK "Security")
-  if(NOT SECURITY_FRAMEWORK)
-     message(FATAL_ERROR "Security framework not found")
-  endif()
-
-  set(SSL_ENABLED ON)
-  set(USE_SECTRANSP ON)
-  list(APPEND CURL_LIBS "${COREFOUNDATION_FRAMEWORK}" "${SECURITY_FRAMEWORK}")
-endif()
-
-if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
   find_library(SYSTEMCONFIGURATION_FRAMEWORK "SystemConfiguration")
   if(NOT SYSTEMCONFIGURATION_FRAMEWORK)
      message(FATAL_ERROR "SystemConfiguration framework not found")
   endif()
-  list(APPEND CURL_LIBS "${SYSTEMCONFIGURATION_FRAMEWORK}")
+
+  list(APPEND CURL_LIBS "-framework CoreFoundation" "-framework SystemConfiguration")
+
+  if(CMAKE_USE_SECTRANSP)
+    find_library(SECURITY_FRAMEWORK "Security")
+    if(NOT SECURITY_FRAMEWORK)
+       message(FATAL_ERROR "Security framework not found")
+    endif()
+
+    set(SSL_ENABLED ON)
+    set(USE_SECTRANSP ON)
+    list(APPEND CURL_LIBS "-framework Security")
+  endif()
 endif()
 
 if(CMAKE_USE_OPENSSL)
@@ -856,15 +893,6 @@ if(CMAKE_USE_LIBSSH2)
     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 "")
     unset(CMAKE_REQUIRED_LIBRARIES)
   endif()
 endif()
@@ -947,7 +975,11 @@ 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)
+  if(WIN32)
+    set(USE_UNIX_SOCKETS ON)
+  else()
+    check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS)
+  endif()
 else()
   unset(USE_UNIX_SOCKETS CACHE)
 endif()
@@ -1065,8 +1097,6 @@ 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("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("idn2.h"           HAVE_IDN2_H)
@@ -1084,9 +1114,7 @@ check_include_file("linux/tcp.h"      HAVE_LINUX_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)
@@ -1149,12 +1177,8 @@ endif()
 check_symbol_exists(getppid       "${CURL_INCLUDES}" HAVE_GETPPID)
 check_symbol_exists(utimes        "${CURL_INCLUDES}" HAVE_UTIMES)
 
-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(closesocket   "${CURL_INCLUDES}" HAVE_CLOSESOCKET)
 check_symbol_exists(sigsetjmp     "${CURL_INCLUDES}" HAVE_SIGSETJMP)
 check_symbol_exists(getpass_r     "${CURL_INCLUDES}" HAVE_GETPASS_R)
@@ -1179,11 +1203,8 @@ 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)
@@ -1250,12 +1271,6 @@ foreach(CURL_TEST
     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
@@ -1265,8 +1280,6 @@ foreach(CURL_TEST
     HAVE_IN_ADDR_T
     HAVE_BOOL_T
     STDC_HEADERS
-    HAVE_INET_NTOA_R_DECL
-    HAVE_INET_NTOA_R_DECL_REENTRANT
     HAVE_GETADDRINFO
     HAVE_FILE_OFFSET_BITS
     HAVE_VARIADIC_MACROS_C99
@@ -1298,13 +1311,9 @@ endforeach()
 
 # 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)
+    HAVE_GETHOSTBYNAME_R_6)
   if(NOT ${CURL_TEST})
     if(${CURL_TEST}_REENTRANT)
       set(NEED_REENTRANT 1)
@@ -1314,9 +1323,6 @@ endforeach()
 
 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)
@@ -1327,11 +1333,6 @@ if(NEED_REENTRANT)
   endforeach()
 endif()
 
-if(HAVE_INET_NTOA_R_DECL_REENTRANT)
-  set(HAVE_INET_NTOA_R_DECL 1)
-  set(NEED_REENTRANT 1)
-endif()
-
 # Check clock_gettime(CLOCK_MONOTONIC, x) support
 curl_internal_test(HAVE_CLOCK_GETTIME_MONOTONIC)
 
@@ -1527,8 +1528,8 @@ endmacro()
 
 # NTLM support requires crypto function adaptions from various SSL libs
 # TODO alternative SSL libs tests for SSP1, GNUTLS, NSS
-if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_MBEDTLS OR
-                                     USE_DARWINSSL OR USE_WIN32_CRYPTO))
+if(NOT (CURL_DISABLE_CRYPTO_AUTH OR CURL_DISABLE_NTLM) AND
+    (USE_OPENSSL OR USE_MBEDTLS OR USE_DARWINSSL OR USE_WIN32_CRYPTO))
   set(use_curl_ntlm_core ON)
 endif()
 
@@ -1556,10 +1557,10 @@ _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
-_add_if("NTLM"          NOT CURL_DISABLE_CRYPTO_AUTH AND
+_add_if("NTLM"          NOT (CURL_DISABLE_CRYPTO_AUTH OR CURL_DISABLE_NTLM) AND
                         (use_curl_ntlm_core OR USE_WINDOWS_SSPI))
 # TODO missing option (autoconf: --enable-ntlm-wb)
-_add_if("NTLM_WB"       NOT CURL_DISABLE_CRYPTO_AUTH AND
+_add_if("NTLM_WB"       NOT (CURL_DISABLE_CRYPTO_AUTH OR CURL_DISABLE_NTLM) AND
                         (use_curl_ntlm_core OR USE_WINDOWS_SSPI) AND
                         NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED)
 # TODO missing option (--enable-tls-srp), depends on GNUTLS_SRP/OPENSSL_SRP
index 55a6a39..7b50b7c 100644 (file)
@@ -25,9 +25,6 @@
 /*
  * If you have libcurl problems, all docs and details are found here:
  *   https://curl.se/libcurl/
- *
- * curl-library mailing list subscription and unsubscription web interface:
- *   https://cool.haxx.se/mailman/listinfo/curl-library/
  */
 
 #ifdef CURL_NO_OLDIES
@@ -74,8 +71,9 @@
 #if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
     defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
     defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
-    defined(__CYGWIN__) || defined(AMIGA) || \
-   (defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
+    defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \
+   (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \
+    defined(__VXWORKS__)
 #include <sys/select.h>
 #endif
 
@@ -541,7 +539,7 @@ typedef enum {
   CURLE_OBSOLETE46,              /* 46 - NOT USED */
   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_SETOPT_OPTION_SYNTAX,    /* 49 - Malformed setopt option */
   CURLE_OBSOLETE50,              /* 50 - NOT USED */
   CURLE_OBSOLETE51,              /* 51 - NOT USED */
   CURLE_GOT_NOTHING,             /* 52 - when this is a specific error */
@@ -636,6 +634,9 @@ typedef enum {
 /* The following were added in 7.21.5, April 2011 */
 #define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION
 
+/* Added for 7.78.0 */
+#define CURLE_TELNET_OPTION_SYNTAX CURLE_SETOPT_OPTION_SYNTAX
+
 /* The following were added in 7.17.1 */
 /* These are scheduled to disappear by 2009 */
 #define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION
@@ -2084,13 +2085,13 @@ typedef enum {
   /* Parameters for V4 signature */
   CURLOPT(CURLOPT_AWS_SIGV4, CURLOPTTYPE_STRINGPOINT, 305),
 
-  /* Same as CURLOPT_SSL_VERIFYPEER but for DOH (DNS-over-HTTPS) servers. */
+  /* Same as CURLOPT_SSL_VERIFYPEER but for DoH (DNS-over-HTTPS) servers. */
   CURLOPT(CURLOPT_DOH_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 306),
 
-  /* Same as CURLOPT_SSL_VERIFYHOST but for DOH (DNS-over-HTTPS) servers. */
+  /* Same as CURLOPT_SSL_VERIFYHOST but for DoH (DNS-over-HTTPS) servers. */
   CURLOPT(CURLOPT_DOH_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 307),
 
-  /* Same as CURLOPT_SSL_VERIFYSTATUS but for DOH (DNS-over-HTTPS) servers. */
+  /* Same as CURLOPT_SSL_VERIFYSTATUS but for DoH (DNS-over-HTTPS) servers. */
   CURLOPT(CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 308),
 
   /* The CA certificates as "blob" used to validate the peer certificate
index a8d5449..9019868 100644 (file)
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "7.77.0"
+#define LIBCURL_VERSION "7.79.1"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 77
-#define LIBCURL_VERSION_PATCH 0
+#define LIBCURL_VERSION_MINOR 79
+#define LIBCURL_VERSION_PATCH 1
 
 /* This is the numeric version of the libcurl version number, meant for easier
    parsing and comparisons 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 0x074d00
+#define LIBCURL_VERSION_NUM 0x074f01
 
 /*
  * This is the date and time when the full source package was created. The
index 7343cb6..1d70880 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2018 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -79,6 +79,7 @@ typedef enum {
 #define CURLU_GUESS_SCHEME (1<<9)       /* legacy curl-style guessing */
 #define CURLU_NO_AUTHORITY (1<<10)      /* Allow empty authority when the
                                            scheme is unknown. */
+#define CURLU_ALLOW_SPACE (1<<11)       /* Allow spaces in the URL */
 
 typedef struct Curl_URL CURLU;
 
index 4ab77fd..36acc3a 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2019 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2019 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -460,7 +460,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
   (void)data;
 #endif
   if(result) {
-    infof(data, "Excessive alt-svc header, ignoring...\n");
+    infof(data, "Excessive alt-svc header, ignoring.");
     return CURLE_OK;
   }
 
@@ -496,7 +496,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
             p++;
           len = p - hostp;
           if(!len || (len >= MAX_ALTSVC_HOSTLEN)) {
-            infof(data, "Excessive alt-svc host name, ignoring...\n");
+            infof(data, "Excessive alt-svc host name, ignoring.");
             dstalpnid = ALPN_none;
           }
           else {
@@ -513,7 +513,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
           /* a port number */
           unsigned long port = strtoul(++p, &end_ptr, 10);
           if(port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
-            infof(data, "Unknown alt-svc port number, ignoring...\n");
+            infof(data, "Unknown alt-svc port number, ignoring.");
             dstalpnid = ALPN_none;
           }
           p = end_ptr;
@@ -579,12 +579,12 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
             as->expires = maxage + time(NULL);
             as->persist = persist;
             Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
-            infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport,
+            infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
                   Curl_alpnid2str(dstalpnid));
           }
         }
         else {
-          infof(data, "Unknown alt-svc protocol \"%s\", skipping...\n",
+          infof(data, "Unknown alt-svc protocol \"%s\", skipping.",
                 alpnbuf);
         }
       }
index 7827847..763a4aa 100644 (file)
@@ -59,7 +59,6 @@
 #include "hostip.h"
 #include "hash.h"
 #include "share.h"
-#include "strerror.h"
 #include "url.h"
 #include "multiif.h"
 #include "inet_pton.h"
 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
 #endif
 
+#if ARES_VERSION >= 0x010601
+/* IPv6 supported since 1.6.1 */
+#define HAVE_CARES_IPV6 1
+#endif
+
+#if ARES_VERSION >= 0x010704
+#define HAVE_CARES_SERVERS_CSV 1
+#define HAVE_CARES_LOCAL_DEV 1
+#define HAVE_CARES_SET_LOCAL 1
+#endif
+
+#if ARES_VERSION >= 0x010b00
+#define HAVE_CARES_PORTS_CSV 1
+#endif
+
+#if ARES_VERSION >= 0x011000
+/* 1.16.0 or later has ares_getaddrinfo */
+#define HAVE_CARES_GETADDRINFO 1
+#endif
+
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
 struct thread_data {
-  int num_pending; /* number of ares_gethostbyname() requests */
+  int num_pending; /* number of outstanding c-ares requests */
   struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
                                     parts */
   int last_status;
@@ -206,7 +225,8 @@ static void destroy_async_data(struct Curl_async *async);
  */
 void Curl_resolver_cancel(struct Curl_easy *data)
 {
-  if(data && data->state.async.resolver)
+  DEBUGASSERT(data);
+  if(data->state.async.resolver)
     ares_cancel((ares_channel)data->state.async.resolver);
   destroy_async_data(&data->state.async);
 }
@@ -489,21 +509,37 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
   return result;
 }
 
+#ifndef HAVE_CARES_GETADDRINFO
+
 /* Connects results to the list */
 static void compound_results(struct thread_data *res,
                              struct Curl_addrinfo *ai)
 {
-  struct Curl_addrinfo *ai_tail;
   if(!ai)
     return;
-  ai_tail = ai;
 
-  while(ai_tail->ai_next)
-    ai_tail = ai_tail->ai_next;
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+  if(res->temp_ai && res->temp_ai->ai_family == PF_INET6) {
+    /* We have results already, put the new IPv6 entries at the head of the
+       list. */
+    struct Curl_addrinfo *temp_ai_tail = res->temp_ai;
+
+    while(temp_ai_tail->ai_next)
+      temp_ai_tail = temp_ai_tail->ai_next;
 
-  /* Add the new results to the list of old results. */
-  ai_tail->ai_next = res->temp_ai;
-  res->temp_ai = ai;
+    temp_ai_tail->ai_next = ai;
+  }
+  else
+#endif /* CURLRES_IPV6 */
+  {
+    /* Add the new results to the list of old results. */
+    struct Curl_addrinfo *ai_tail = ai;
+    while(ai_tail->ai_next)
+      ai_tail = ai_tail->ai_next;
+
+    ai_tail->ai_next = res->temp_ai;
+    res->temp_ai = ai;
+  }
 }
 
 /*
@@ -605,7 +641,98 @@ static void query_completed_cb(void *arg,  /* (struct connectdata *) */
     }
   }
 }
+#else
+/* c-ares 1.16.0 or later */
+
+/*
+ * ares2addr() converts an address list provided by c-ares to an internal
+ * libcurl compatible list
+ */
+static struct Curl_addrinfo *ares2addr(struct ares_addrinfo_node *node)
+{
+  /* traverse the ares_addrinfo_node list */
+  struct ares_addrinfo_node *ai;
+  struct Curl_addrinfo *cafirst = NULL;
+  struct Curl_addrinfo *calast = NULL;
+  int error = 0;
+
+  for(ai = node; ai != NULL; ai = ai->ai_next) {
+    size_t ss_size;
+    struct Curl_addrinfo *ca;
+    /* ignore elements with unsupported address family, */
+    /* settle family-specific sockaddr structure size.  */
+    if(ai->ai_family == AF_INET)
+      ss_size = sizeof(struct sockaddr_in);
+#ifdef ENABLE_IPV6
+    else if(ai->ai_family == AF_INET6)
+      ss_size = sizeof(struct sockaddr_in6);
+#endif
+    else
+      continue;
+
+    /* ignore elements without required address info */
+    if(!ai->ai_addr || !(ai->ai_addrlen > 0))
+      continue;
+
+    /* ignore elements with bogus address size */
+    if((size_t)ai->ai_addrlen < ss_size)
+      continue;
+
+    ca = malloc(sizeof(struct Curl_addrinfo) + ss_size);
+    if(!ca) {
+      error = EAI_MEMORY;
+      break;
+    }
+
+    /* copy each structure member individually, member ordering, */
+    /* size, or padding might be different for each platform.    */
+
+    ca->ai_flags     = ai->ai_flags;
+    ca->ai_family    = ai->ai_family;
+    ca->ai_socktype  = ai->ai_socktype;
+    ca->ai_protocol  = ai->ai_protocol;
+    ca->ai_addrlen   = (curl_socklen_t)ss_size;
+    ca->ai_addr      = NULL;
+    ca->ai_canonname = NULL;
+    ca->ai_next      = NULL;
+
+    ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
+    memcpy(ca->ai_addr, ai->ai_addr, ss_size);
+
+    /* if the return list is empty, this becomes the first element */
+    if(!cafirst)
+      cafirst = ca;
+
+    /* add this element last in the return list */
+    if(calast)
+      calast->ai_next = ca;
+    calast = ca;
+  }
+
+  /* if we failed, destroy the Curl_addrinfo list */
+  if(error) {
+    Curl_freeaddrinfo(cafirst);
+    cafirst = NULL;
+  }
+
+  return cafirst;
+}
+
+static void addrinfo_cb(void *arg, int status, int timeouts,
+                        struct ares_addrinfo *result)
+{
+  struct Curl_easy *data = (struct Curl_easy *)arg;
+  struct thread_data *res = data->state.async.tdata;
+  (void)timeouts;
+  if(ARES_SUCCESS == status) {
+    res->temp_ai = ares2addr(result->nodes);
+    res->last_status = CURL_ASYNC_SUCCESS;
+    ares_freeaddrinfo(result);
+  }
+  res->num_pending--;
+}
 
+#endif
 /*
  * Curl_resolver_getaddrinfo() - when using ares
  *
@@ -643,8 +770,28 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
     /* initial status - failed */
     res->last_status = ARES_ENOTFOUND;
 
-#if ARES_VERSION >= 0x010601
-    /* IPv6 supported by c-ares since 1.6.1 */
+#ifdef HAVE_CARES_GETADDRINFO
+    {
+      struct ares_addrinfo_hints hints;
+      char service[12];
+      int pf = PF_INET;
+      memset(&hints, 0, sizeof(hints));
+#ifdef CURLRES_IPV6
+      if(Curl_ipv6works(data))
+        /* The stack seems to be IPv6-enabled */
+        pf = PF_UNSPEC;
+#endif /* CURLRES_IPV6 */
+      hints.ai_family = pf;
+      hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
+        SOCK_STREAM : SOCK_DGRAM;
+      msnprintf(service, sizeof(service), "%d", port);
+      res->num_pending = 1;
+      ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
+                       service, &hints, addrinfo_cb, data);
+    }
+#else
+
+#ifdef HAVE_CARES_IPV6
     if(Curl_ipv6works(data)) {
       /* The stack seems to be IPv6-enabled */
       res->num_pending = 2;
@@ -656,7 +803,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                           PF_INET6, query_completed_cb, data);
     }
     else
-#endif /* ARES_VERSION >= 0x010601 */
+#endif
     {
       res->num_pending = 1;
 
@@ -665,7 +812,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                          hostname, PF_INET,
                          query_completed_cb, data);
     }
-
+#endif
     *waitp = 1; /* expect asynchronous response */
   }
   return NULL; /* no struct yet */
@@ -686,8 +833,8 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
   if(!(servers && servers[0]))
     return CURLE_OK;
 
-#if (ARES_VERSION >= 0x010704)
-#if (ARES_VERSION >= 0x010b00)
+#ifdef HAVE_CARES_SERVERS_CSV
+#ifdef HAVE_CARES_PORTS_CSV
   ares_result = ares_set_servers_ports_csv(data->state.async.resolver,
                                            servers);
 #else
@@ -717,7 +864,7 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
 CURLcode Curl_set_dns_interface(struct Curl_easy *data,
                                 const char *interf)
 {
-#if (ARES_VERSION >= 0x010704)
+#ifdef HAVE_CARES_LOCAL_DEV
   if(!interf)
     interf = "";
 
@@ -734,7 +881,7 @@ CURLcode Curl_set_dns_interface(struct Curl_easy *data,
 CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
                                 const char *local_ip4)
 {
-#if (ARES_VERSION >= 0x010704)
+#ifdef HAVE_CARES_SET_LOCAL
   struct in_addr a4;
 
   if((!local_ip4) || (local_ip4[0] == 0)) {
@@ -760,7 +907,7 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
 CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
                                 const char *local_ip6)
 {
-#if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6)
+#if defined(HAVE_CARES_SET_LOCAL) && defined(ENABLE_IPV6)
   unsigned char a6[INET6_ADDRSTRLEN];
 
   if((!local_ip6) || (local_ip6[0] == 0)) {
index 36f68cb..149172a 100644 (file)
@@ -68,7 +68,6 @@
 #include "hostip.h"
 #include "hash.h"
 #include "share.h"
-#include "strerror.h"
 #include "url.h"
 #include "multiif.h"
 #include "inet_ntop.h"
index 81f589e..26635cd 100644 (file)
@@ -124,6 +124,17 @@ static int hyper_each_header(void *userdata,
   size_t len;
   char *headp;
   CURLcode result;
+  int writetype;
+
+  if(name_len + value_len + 2 > CURL_MAX_HTTP_HEADER) {
+    failf(data, "Too long response header");
+    data->state.hresult = CURLE_OUT_OF_MEMORY;
+    return HYPER_ITER_BREAK;
+  }
+
+  if(!data->req.bytecount)
+    Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+
   Curl_dyn_reset(&data->state.headerb);
   if(name_len) {
     if(Curl_dyn_addf(&data->state.headerb, "%.*s: %.*s\r\n",
@@ -145,7 +156,10 @@ static int hyper_each_header(void *userdata,
 
   Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
 
-  result = Curl_client_write(data, CLIENTWRITE_HEADER, headp, len);
+  writetype = CLIENTWRITE_HEADER;
+  if(data->set.include_header)
+    writetype |= CLIENTWRITE_BODY;
+  result = Curl_client_write(data, writetype, headp, len);
   if(result) {
     data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
     return HYPER_ITER_BREAK;
@@ -162,13 +176,43 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
   size_t len = hyper_buf_len(chunk);
   struct Curl_easy *data = (struct Curl_easy *)userdata;
   struct SingleRequest *k = &data->req;
-  CURLcode result;
+  CURLcode result = CURLE_OK;
 
   if(0 == k->bodywrites++) {
     bool done = FALSE;
-    result = Curl_http_firstwrite(data, data->conn, &done);
+#if defined(USE_NTLM)
+    struct connectdata *conn = data->conn;
+    if(conn->bits.close &&
+       (((data->req.httpcode == 401) &&
+         (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
+        ((data->req.httpcode == 407) &&
+         (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
+      infof(data, "Connection closed while negotiating NTLM");
+      data->state.authproblem = TRUE;
+      Curl_safefree(data->req.newurl);
+    }
+#endif
+    if(data->state.expect100header) {
+      Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+      if(data->req.httpcode < 400) {
+        k->exp100 = EXP100_SEND_DATA;
+        if(data->hyp.exp100_waker) {
+          hyper_waker_wake(data->hyp.exp100_waker);
+          data->hyp.exp100_waker = NULL;
+        }
+      }
+      else { /* >= 4xx */
+        k->exp100 = EXP100_FAILED;
+      }
+    }
+    if(data->state.hconnect && (data->req.httpcode/100 != 2)) {
+      done = TRUE;
+      result = CURLE_OK;
+    }
+    else
+      result = Curl_http_firstwrite(data, data->conn, &done);
     if(result || done) {
-      infof(data, "Return early from hyper_body_chunk\n");
+      infof(data, "Return early from hyper_body_chunk");
       data->state.hresult = result;
       return HYPER_ITER_BREAK;
     }
@@ -207,11 +251,15 @@ static CURLcode status_line(struct Curl_easy *data,
   CURLcode result;
   size_t len;
   const char *vstr;
+  int writetype;
   vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" :
     (http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0");
   conn->httpversion =
     http_version == HYPER_HTTP_VERSION_1_1 ? 11 :
     (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
+  if(http_version == HYPER_HTTP_VERSION_1_0)
+    data->state.httpwant = CURL_HTTP_VERSION_1_0;
+
   data->req.httpcode = http_status;
 
   result = Curl_http_statusline(data, conn);
@@ -229,7 +277,10 @@ static CURLcode status_line(struct Curl_easy *data,
   len = Curl_dyn_len(&data->state.headerb);
   Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
              len);
-  result = Curl_client_write(data, CLIENTWRITE_HEADER,
+  writetype = CLIENTWRITE_HEADER;
+  if(data->set.include_header)
+    writetype |= CLIENTWRITE_BODY;
+  result = Curl_client_write(data, writetype,
                              Curl_dyn_ptr(&data->state.headerb), len);
   if(result) {
     data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
@@ -270,8 +321,25 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
   const uint8_t *reasonp;
   size_t reason_len;
   CURLcode result = CURLE_OK;
+  struct SingleRequest *k = &data->req;
   (void)conn;
 
+  if(k->exp100 > EXP100_SEND_DATA) {
+    struct curltime now = Curl_now();
+    timediff_t ms = Curl_timediff(now, k->start100);
+    if(ms >= data->set.expect_100_timeout) {
+      /* we've waited long enough, continue anyway */
+      k->exp100 = EXP100_SEND_DATA;
+      k->keepon |= KEEP_SEND;
+      Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+      infof(data, "Done waiting for 100-continue");
+      if(data->hyp.exp100_waker) {
+        hyper_waker_wake(data->hyp.exp100_waker);
+        data->hyp.exp100_waker = NULL;
+      }
+    }
+  }
+
   if(select_res & CURL_CSELECT_IN) {
     if(h->read_waker)
       hyper_waker_wake(h->read_waker);
@@ -305,19 +373,22 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
     hyper_task_free(task);
 
     if(t == HYPER_TASK_ERROR) {
-      hyper_code errnum = hyper_error_code(hypererr);
-      if(errnum == HYPERE_ABORTED_BY_CALLBACK) {
+      if(data->state.hresult) {
         /* override Hyper's view, might not even be an error */
         result = data->state.hresult;
-        infof(data, "hyperstream is done (by early callback)\n");
+        infof(data, "hyperstream is done (by early callback)");
       }
       else {
         uint8_t errbuf[256];
         size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
         hyper_code code = hyper_error_code(hypererr);
         failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
-        if((code == HYPERE_UNEXPECTED_EOF) && !data->req.bytecount)
+        if(code == HYPERE_ABORTED_BY_CALLBACK)
+          result = CURLE_OK;
+        else if((code == HYPERE_UNEXPECTED_EOF) && !data->req.bytecount)
           result = CURLE_GOT_NOTHING;
+        else if(code == HYPERE_INVALID_PEER_MESSAGE)
+          result = CURLE_UNSUPPORTED_PROTOCOL; /* maybe */
         else
           result = CURLE_RECV_ERROR;
       }
@@ -328,10 +399,15 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
     else if(h->endtask == task) {
       /* end of transfer */
       *done = TRUE;
-      infof(data, "hyperstream is done!\n");
+      infof(data, "hyperstream is done!");
+      if(!k->bodywrites) {
+        /* hyper doesn't always call the body write callback */
+        bool stilldone;
+        result = Curl_http_firstwrite(data, data->conn, &stilldone);
+      }
       break;
     }
-    else if(t != HYPER_TASK_RESPONSE && t != HYPER_TASK_EMPTY) {
+    else if(t != HYPER_TASK_RESPONSE) {
       *didwhat = KEEP_RECV;
       break;
     }
@@ -472,7 +548,7 @@ CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
 
     if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen,
                                       (uint8_t *)v, vlen)) {
-      failf(data, "hyper_headers_add host");
+      failf(data, "hyper refused to add header '%s'", line);
       return CURLE_OUT_OF_MEMORY;
     }
     if(data->set.verbose) {
@@ -485,7 +561,7 @@ CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
         free(ptr);
       }
       else
-        Curl_debug(data, CURLINFO_HEADER_OUT, (char *)line, linelen);
+        Curl_debug(data, CURLINFO_HEADER_OUT, (char *)n, linelen);
     }
     numh++;
     n += linelen;
@@ -526,12 +602,32 @@ static int uploadpostfields(void *userdata, hyper_context *ctx,
 {
   struct Curl_easy *data = (struct Curl_easy *)userdata;
   (void)ctx;
+  if(data->req.exp100 > EXP100_SEND_DATA) {
+    if(data->req.exp100 == EXP100_FAILED)
+      return HYPER_POLL_ERROR;
+
+    /* still waiting confirmation */
+    if(data->hyp.exp100_waker)
+      hyper_waker_free(data->hyp.exp100_waker);
+    data->hyp.exp100_waker = hyper_context_waker(ctx);
+    return HYPER_POLL_PENDING;
+  }
   if(data->req.upload_done)
     *chunk = NULL; /* nothing more to deliver */
   else {
     /* send everything off in a single go */
-    *chunk = hyper_buf_copy(data->set.postfields,
-                            (size_t)data->req.p.http->postsize);
+    hyper_buf *copy = hyper_buf_copy(data->set.postfields,
+                                     (size_t)data->req.p.http->postsize);
+    if(copy)
+      *chunk = copy;
+    else {
+      data->state.hresult = CURLE_OUT_OF_MEMORY;
+      return HYPER_POLL_ERROR;
+    }
+    /* increasing the writebytecount here is a little premature but we
+       don't know exactly when the body is sent*/
+    data->req.writebytecount += (size_t)data->req.p.http->postsize;
+    Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
     data->req.upload_done = TRUE;
   }
   return HYPER_POLL_READY;
@@ -542,16 +638,41 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
 {
   size_t fillcount;
   struct Curl_easy *data = (struct Curl_easy *)userdata;
-  CURLcode result =
-    Curl_fillreadbuffer(data, data->set.upload_buffer_size, &fillcount);
+  CURLcode result;
   (void)ctx;
-  if(result)
+
+  if(data->req.exp100 > EXP100_SEND_DATA) {
+    if(data->req.exp100 == EXP100_FAILED)
+      return HYPER_POLL_ERROR;
+
+    /* still waiting confirmation */
+    if(data->hyp.exp100_waker)
+      hyper_waker_free(data->hyp.exp100_waker);
+    data->hyp.exp100_waker = hyper_context_waker(ctx);
+    return HYPER_POLL_PENDING;
+  }
+
+  result = Curl_fillreadbuffer(data, data->set.upload_buffer_size, &fillcount);
+  if(result) {
+    data->state.hresult = result;
     return HYPER_POLL_ERROR;
+  }
   if(!fillcount)
     /* done! */
     *chunk = NULL;
-  else
-    *chunk = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
+  else {
+    hyper_buf *copy = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
+    if(copy)
+      *chunk = copy;
+    else {
+      data->state.hresult = CURLE_OUT_OF_MEMORY;
+      return HYPER_POLL_ERROR;
+    }
+    /* increasing the writebytecount here is a little premature but we
+       don't know exactly when the body is sent*/
+    data->req.writebytecount += fillcount;
+    Curl_pgrsSetUploadCounter(data, fillcount);
+  }
   return HYPER_POLL_READY;
 }
 
@@ -566,6 +687,7 @@ static CURLcode bodysend(struct Curl_easy *data,
                          hyper_request *hyperreq,
                          Curl_HttpReq httpreq)
 {
+  struct HTTP *http = data->req.p.http;
   CURLcode result = CURLE_OK;
   struct dynbuf req;
   if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
@@ -598,6 +720,7 @@ static CURLcode bodysend(struct Curl_easy *data,
       result = CURLE_OUT_OF_MEMORY;
     }
   }
+  http->sending = HTTPSEND_BODY;
   return result;
 }
 
@@ -616,6 +739,48 @@ static CURLcode cookies(struct Curl_easy *data,
   return result;
 }
 
+/* called on 1xx responses */
+static void http1xx_cb(void *arg, struct hyper_response *resp)
+{
+  struct Curl_easy *data = (struct Curl_easy *)arg;
+  hyper_headers *headers = NULL;
+  CURLcode result = CURLE_OK;
+  uint16_t http_status;
+  int http_version;
+  const uint8_t *reasonp;
+  size_t reason_len;
+
+  infof(data, "Got HTTP 1xx informational");
+
+  http_status = hyper_response_status(resp);
+  http_version = hyper_response_version(resp);
+  reasonp = hyper_response_reason_phrase(resp);
+  reason_len = hyper_response_reason_phrase_len(resp);
+
+  result = status_line(data, data->conn,
+                       http_status, http_version, reasonp, reason_len);
+  if(!result) {
+    headers = hyper_response_headers(resp);
+    if(!headers) {
+      failf(data, "hyperstream: couldn't get 1xx response headers");
+      result = CURLE_RECV_ERROR;
+    }
+  }
+  data->state.hresult = result;
+
+  if(!result) {
+    /* the headers are already received */
+    hyper_headers_foreach(headers, hyper_each_header, data);
+    /* this callback also sets data->state.hresult on error */
+
+    if(empty_header(data))
+      result = CURLE_OUT_OF_MEMORY;
+  }
+
+  if(data->state.hresult)
+    infof(data, "ERROR in 1xx, bail out!");
+}
+
 /*
  * 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
@@ -633,20 +798,20 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   hyper_request *req = NULL;
   hyper_headers *headers = NULL;
   hyper_task *handshake = NULL;
-  hyper_error *hypererr = NULL;
   CURLcode result;
   const char *p_accept; /* Accept: string */
   const char *method;
   Curl_HttpReq httpreq;
   bool h2 = FALSE;
   const char *te = NULL; /* transfer-encoding */
+  hyper_code rc;
 
   /* Always consider the DO phase done after this function call, even if there
      may be parts of the request that is not yet sent, since we can deal with
      the rest of the request in the PERFORM phase. */
   *done = TRUE;
 
-  infof(data, "Time for the Hyper dance\n");
+  infof(data, "Time for the Hyper dance");
   memset(h, 0, sizeof(struct hyptransfer));
 
   result = Curl_http_host(data, conn);
@@ -743,7 +908,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     goto error;
   }
 
-  if(data->state.httpwant == CURL_HTTP_VERSION_1_0) {
+  if(!Curl_use_http_1_1plus(data, conn)) {
     if(HYPERE_OK != hyper_request_set_version(req,
                                               HYPER_HTTP_VERSION_1_0)) {
       failf(data, "error setting HTTP version");
@@ -766,6 +931,10 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     goto error;
   }
 
+  rc = hyper_request_on_informational(req, http1xx_cb, data);
+  if(rc)
+    return CURLE_OUT_OF_MEMORY;
+
   result = Curl_http_body(data, conn, httpreq, &te);
   if(result)
     return result;
@@ -830,6 +999,15 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   else
     Curl_safefree(data->state.aptr.accept_encoding);
 
+#ifdef HAVE_LIBZ
+  /* we only consider transfer-encoding magic if libz support is built-in */
+  result = Curl_transferencode(data);
+  if(result)
+    return result;
+  if(Curl_hyper_header(data, headers, data->state.aptr.te))
+    goto error;
+#endif
+
   result = cookies(data, conn, headers);
   if(result)
     return result;
@@ -862,25 +1040,21 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
 
   hyper_clientconn_free(client);
 
-  do {
-    task = hyper_executor_poll(h->exec);
-    if(task) {
-      bool error = hyper_task_type(task) == HYPER_TASK_ERROR;
-      if(error)
-        hypererr = hyper_task_value(task);
-      hyper_task_free(task);
-      if(error)
-        goto error;
-    }
-  } while(task);
-
   if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
     /* HTTP GET/HEAD download */
     Curl_pgrsSetUploadSize(data, 0); /* nothing */
     Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
   }
   conn->datastream = Curl_hyper_stream;
-
+  if(data->state.expect100header)
+    /* Timeout count starts now since with Hyper we don't know exactly when
+       the full request has been sent. */
+    data->req.start100 = Curl_now();
+
+  /* clear userpwd and proxyuserpwd to avoid re-using old credentials
+   * from re-used connections */
+  Curl_safefree(data->state.aptr.userpwd);
+  Curl_safefree(data->state.aptr.proxyuserpwd);
   return CURLE_OK;
   error:
 
@@ -893,13 +1067,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if(handshake)
     hyper_task_free(handshake);
 
-  if(hypererr) {
-    uint8_t errbuf[256];
-    size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
-    hyper_code code = hyper_error_code(hypererr);
-    failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
-    hyper_error_free(hypererr);
-  }
   return CURLE_OUT_OF_MEMORY;
 }
 
@@ -918,6 +1085,10 @@ void Curl_hyper_done(struct Curl_easy *data)
     hyper_waker_free(h->write_waker);
     h->write_waker = NULL;
   }
+  if(h->exp100_waker) {
+    hyper_waker_free(h->exp100_waker);
+    h->exp100_waker = NULL;
+  }
 }
 
 #endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */
index d60ed78..d63defe 100644 (file)
@@ -33,6 +33,7 @@ struct hyptransfer {
   hyper_waker *read_waker;
   const hyper_executor *exec;
   hyper_task *endtask;
+  hyper_waker *exp100_waker;
 };
 
 size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
index 5453c00..f5ba8ff 100644 (file)
@@ -34,6 +34,7 @@
 #include "share.h"
 #include "sigpipe.h"
 #include "connect.h"
+#include "strcase.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -161,6 +162,7 @@ static void hashkey(struct connectdata *conn, char *buf,
 
   /* put the number first so that the hostname gets cut off if too long */
   msnprintf(buf, len, "%ld%s", port, hostname);
+  Curl_strntolower(buf, buf, len);
 }
 
 /* Returns number of connections currently held in the connection cache.
@@ -264,7 +266,7 @@ CURLcode Curl_conncache_add_conn(struct Curl_easy *data)
   connc->num_conn++;
 
   DEBUGF(infof(data, "Added connection %ld. "
-               "The cache now contains %zu members\n",
+               "The cache now contains %zu members",
                conn->connection_id, connc->num_conn));
 
   unlock:
@@ -298,7 +300,7 @@ void Curl_conncache_remove_conn(struct Curl_easy *data,
     conn->bundle = NULL; /* removed from it */
     if(connc) {
       connc->num_conn--;
-      DEBUGF(infof(data, "The cache now contains %zu members\n",
+      DEBUGF(infof(data, "The cache now contains %zu members",
                    connc->num_conn));
     }
     if(lock) {
@@ -408,7 +410,7 @@ bool Curl_conncache_return_conn(struct Curl_easy *data,
   conn->lastused = Curl_now(); /* it was used up until now */
   if(maxconnects > 0 &&
      Curl_conncache_size(data) > maxconnects) {
-    infof(data, "Connection cache is full, closing the oldest one.\n");
+    infof(data, "Connection cache is full, closing the oldest one");
 
     conn_candidate = Curl_conncache_extract_oldest(data);
     if(conn_candidate) {
@@ -464,7 +466,7 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
     /* remove it to prevent another thread from nicking it */
     bundle_remove_conn(bundle, conn_candidate);
     data->state.conn_cache->num_conn--;
-    DEBUGF(infof(data, "The cache now contains %zu members\n",
+    DEBUGF(infof(data, "The cache now contains %zu members",
                  data->state.conn_cache->num_conn));
   }
 
@@ -526,7 +528,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
     /* remove it to prevent another thread from nicking it */
     bundle_remove_conn(bundle_candidate, conn_candidate);
     connc->num_conn--;
-    DEBUGF(infof(data, "The cache now contains %zu members\n",
+    DEBUGF(infof(data, "The cache now contains %zu members",
                  connc->num_conn));
   }
   CONNCACHE_UNLOCK(data);
index d9317f3..d61b037 100644 (file)
@@ -111,7 +111,7 @@ tcpkeepalive(struct Curl_easy *data,
   /* only set IDLE and INTVL if setting KEEPALIVE is successful */
   if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
         (void *)&optval, sizeof(optval)) < 0) {
-    infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
+    infof(data, "Failed to set SO_KEEPALIVE on fd %d", sockfd);
   }
   else {
 #if defined(SIO_KEEPALIVE_VALS)
@@ -126,7 +126,7 @@ tcpkeepalive(struct Curl_easy *data,
     vals.keepaliveinterval = optval;
     if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
                 NULL, 0, &dummy, NULL, NULL) != 0) {
-      infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n",
+      infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d",
             (int)sockfd, WSAGetLastError());
     }
 #else
@@ -135,7 +135,7 @@ tcpkeepalive(struct Curl_easy *data,
     KEEPALIVE_FACTOR(optval);
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
           (void *)&optval, sizeof(optval)) < 0) {
-      infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
+      infof(data, "Failed to set TCP_KEEPIDLE on fd %d", sockfd);
     }
 #endif
 #ifdef TCP_KEEPINTVL
@@ -143,7 +143,7 @@ tcpkeepalive(struct Curl_easy *data,
     KEEPALIVE_FACTOR(optval);
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
           (void *)&optval, sizeof(optval)) < 0) {
-      infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
+      infof(data, "Failed to set TCP_KEEPINTVL on fd %d", sockfd);
     }
 #endif
 #ifdef TCP_KEEPALIVE
@@ -152,7 +152,7 @@ tcpkeepalive(struct Curl_easy *data,
     KEEPALIVE_FACTOR(optval);
     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
           (void *)&optval, sizeof(optval)) < 0) {
-      infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd);
+      infof(data, "Failed to set TCP_KEEPALIVE on fd %d", sockfd);
     }
 #endif
 #endif
@@ -331,7 +331,7 @@ static CURLcode bindlocal(struct Curl_easy *data,
           /*
            * We now have the numerical IP address in the 'myhost' buffer
            */
-          infof(data, "Local Interface %s is ip %s using address family %i\n",
+          infof(data, "Local Interface %s is ip %s using address family %i",
                 dev, myhost, af);
           done = 1;
           break;
@@ -364,7 +364,7 @@ static CURLcode bindlocal(struct Curl_easy *data,
       if(h) {
         /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
         Curl_printable_address(h->addr, myhost, sizeof(myhost));
-        infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
+        infof(data, "Name '%s' family %i resolved to '%s' family %i",
               dev, af, myhost, h->addr->ai_family);
         Curl_resolv_unlock(data, h);
         if(af != h->addr->ai_family) {
@@ -458,13 +458,13 @@ static CURLcode bindlocal(struct Curl_easy *data,
               error, Curl_strerror(error, buffer, sizeof(buffer)));
         return CURLE_INTERFACE_FAILED;
       }
-      infof(data, "Local port: %hu\n", port);
+      infof(data, "Local port: %hu", port);
       conn->bits.bound = TRUE;
       return CURLE_OK;
     }
 
     if(--portnum > 0) {
-      infof(data, "Bind to local port %hu failed, trying next\n", port);
+      infof(data, "Bind to local port %hu failed, trying next", port);
       port++; /* try next port */
       /* We re-use/clobber the port variable here below */
       if(sock->sa_family == AF_INET)
@@ -589,12 +589,10 @@ static CURLcode trynextip(struct Curl_easy *data,
     struct Curl_addrinfo *ai = conn->tempaddr[tempindex];
 
     while(ai) {
-      if(ai) {
-        result = singleipconnect(data, conn, ai, tempindex);
-        if(result == CURLE_COULDNT_CONNECT) {
-          ai = ainext(conn, tempindex, TRUE);
-          continue;
-        }
+      result = singleipconnect(data, conn, ai, tempindex);
+      if(result == CURLE_COULDNT_CONNECT) {
+        ai = ainext(conn, tempindex, TRUE);
+        continue;
       }
       break;
     }
@@ -753,10 +751,9 @@ void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn,
   int local_port = -1;
 
   if(conn->transport == TRNSPRT_TCP) {
-    if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
+    if(!conn->bits.reuse && !conn->bits.tcp_fastopen)
       Curl_conninfo_remote(data, conn, sockfd);
-      Curl_conninfo_local(data, sockfd, local_ip, &local_port);
-    }
+    Curl_conninfo_local(data, sockfd, local_ip, &local_port);
   } /* end of TCP-only section */
 
   /* persist connection info in session handle */
@@ -872,15 +869,6 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
 
   now = Curl_now();
 
-  /* figure out how long time we have left to connect */
-  allow = Curl_timeleft(data, &now, TRUE);
-
-  if(allow < 0) {
-    /* time-out, bail out, go home */
-    failf(data, "Connection time-out");
-    return CURLE_OPERATION_TIMEDOUT;
-  }
-
   if(SOCKS_STATE(conn->cnnct.state)) {
     /* still doing SOCKS */
     result = connect_SOCKS(data, sockindex, connected);
@@ -930,7 +918,7 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
       if(Curl_timediff(now, conn->connecttime) >=
          conn->timeoutms_per_addr[i]) {
         infof(data, "After %" CURL_FORMAT_TIMEDIFF_T
-              "ms connect time, move on!\n", conn->timeoutms_per_addr[i]);
+              "ms connect time, move on!", conn->timeoutms_per_addr[i]);
         error = ETIMEDOUT;
       }
 
@@ -989,11 +977,12 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
         char buffer[STRERROR_LEN];
         Curl_printable_address(conn->tempaddr[i], ipaddress,
                                sizeof(ipaddress));
-        infof(data, "connect to %s port %ld failed: %s\n",
+        infof(data, "connect to %s port %u failed: %s",
               ipaddress, conn->port,
               Curl_strerror(error, buffer, sizeof(buffer)));
 #endif
 
+        allow = Curl_timeleft(data, &now, TRUE);
         conn->timeoutms_per_addr[i] = conn->tempaddr[i]->ai_next == NULL ?
           allow : allow / 2;
         ainext(conn, i, TRUE);
@@ -1006,6 +995,21 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
     }
   }
 
+  /*
+   * Now that we've checked whether we are connected, check whether we've
+   * already timed out.
+   *
+   * First figure out how long time we have left to connect */
+
+  allow = Curl_timeleft(data, &now, TRUE);
+
+  if(allow < 0) {
+    /* time-out, bail out, go home */
+    failf(data, "Connection timeout after %ld ms",
+          Curl_timediff(now, data->progress.t_startsingle));
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
   if(result &&
      (conn->tempsock[0] == CURL_SOCKET_BAD) &&
      (conn->tempsock[1] == CURL_SOCKET_BAD)) {
@@ -1031,9 +1035,11 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
     else
       hostname = conn->host.name;
 
-    failf(data, "Failed to connect to %s port %ld: %s",
-          hostname, conn->port,
-          Curl_strerror(error, buffer, sizeof(buffer)));
+    failf(data, "Failed to connect to %s port %u after "
+                "%" CURL_FORMAT_TIMEDIFF_T " ms: %s",
+        hostname, conn->port,
+        Curl_timediff(now, data->progress.t_startsingle),
+        Curl_strerror(error, buffer, sizeof(buffer)));
 
     Curl_quic_disconnect(data, conn, 0);
     Curl_quic_disconnect(data, conn, 1);
@@ -1065,7 +1071,7 @@ static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
 
   if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
                 sizeof(onoff)) < 0)
-    infof(data, "Could not set TCP_NODELAY: %s\n",
+    infof(data, "Could not set TCP_NODELAY: %s",
           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
 #else
   (void)data;
@@ -1084,9 +1090,11 @@ static void nosigpipe(struct Curl_easy *data,
   int onoff = 1;
   if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
                 sizeof(onoff)) < 0) {
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
     char buffer[STRERROR_LEN];
-    infof(data, "Could not set SO_NOSIGPIPE: %s\n",
+    infof(data, "Could not set SO_NOSIGPIPE: %s",
           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+#endif
   }
 }
 #else
@@ -1180,7 +1188,7 @@ static CURLcode singleipconnect(struct Curl_easy *data,
     Curl_closesocket(data, conn, sockfd);
     return CURLE_OK;
   }
-  infof(data, "  Trying %s:%d...\n", ipaddress, port);
+  infof(data, "  Trying %s:%d...", ipaddress, port);
 
 #ifdef ENABLE_IPV6
   is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
@@ -1271,7 +1279,7 @@ static CURLcode singleipconnect(struct Curl_easy *data,
 #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
       if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
                     (void *)&optval, sizeof(optval)) < 0)
-        infof(data, "Failed to enable TCP Fast Open on fd %d\n", sockfd);
+        infof(data, "Failed to enable TCP Fast Open on fd %d", sockfd);
 
       rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
 #elif defined(MSG_FASTOPEN) /* old Linux */
@@ -1321,7 +1329,7 @@ static CURLcode singleipconnect(struct Curl_easy *data,
 
     default:
       /* unknown error, fallthrough and try another address! */
-      infof(data, "Immediate connect fail for %s: %s\n",
+      infof(data, "Immediate connect fail for %s: %s",
             ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
       data->state.os_errno = error;
 
@@ -1394,7 +1402,7 @@ CURLcode Curl_connecthost(struct Curl_easy *data,
 
   ainext(conn, 1, FALSE); /* assigns conn->tempaddr[1] accordingly */
 
-  DEBUGF(infof(data, "family0 == %s, family1 == %s\n",
+  DEBUGF(infof(data, "family0 == %s, family1 == %s",
                conn->tempfamily[0] == AF_INET ? "v4" : "v6",
                conn->tempfamily[1] == AF_INET ? "v4" : "v6"));
 
index 941623f..b7531f7 100644 (file)
@@ -95,7 +95,6 @@ Example set of cookies:
 #include "strcase.h"
 #include "curl_get_line.h"
 #include "curl_memrchr.h"
-#include "inet_pton.h"
 #include "parsedate.h"
 #include "rand.h"
 #include "rename.h"
@@ -147,31 +146,6 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)
 }
 
 /*
- * isip
- *
- * Returns true if the given string is an IPv4 or IPv6 address (if IPv6 has
- * been enabled while building libcurl, and false otherwise.
- */
-static bool isip(const char *domain)
-{
-  struct in_addr addr;
-#ifdef ENABLE_IPV6
-  struct in6_addr addr6;
-#endif
-
-  if(Curl_inet_pton(AF_INET, domain, &addr)
-#ifdef ENABLE_IPV6
-     || Curl_inet_pton(AF_INET6, domain, &addr6)
-#endif
-    ) {
-    /* domain name given as IP address */
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-/*
  * matching cookie path and url path
  * RFC6265 5.1.4 Paths and Path-Match
  */
@@ -303,7 +277,7 @@ static size_t cookiehash(const char * const domain)
   const char *top;
   size_t len;
 
-  if(!domain || isip(domain))
+  if(!domain || Curl_host_is_ipnum(domain))
     return 0;
 
   top = get_top_domain(domain, &len);
@@ -366,7 +340,7 @@ void Curl_cookie_loadfiles(struct Curl_easy *data)
          * Failure may be due to OOM or a bad cookie; both are ignored
          * but only the first should be
          */
-        infof(data, "ignoring failed cookie_init for %s\n", list->data);
+        infof(data, "ignoring failed cookie_init for %s", list->data);
       else
         data->cookies = newcookies;
       list = list->next;
@@ -397,7 +371,9 @@ static void strstore(char **str, const char *newstr)
  *
  * Remove expired cookies from the hash by inspecting the expires timestamp on
  * each cookie in the hash, freeing and deleting any where the timestamp is in
- * the past.
+ * the past.  If the cookiejar has recorded the next timestamp at which one or
+ * more cookies expire, then processing will exit early in case this timestamp
+ * is in the future.
  */
 static void remove_expired(struct CookieInfo *cookies)
 {
@@ -405,6 +381,20 @@ static void remove_expired(struct CookieInfo *cookies)
   curl_off_t now = (curl_off_t)time(NULL);
   unsigned int i;
 
+  /*
+   * If the earliest expiration timestamp in the jar is in the future we can
+   * skip scanning the whole jar and instead exit early as there won't be any
+   * cookies to evict.  If we need to evict however, reset the next_expiration
+   * counter in order to track the next one. In case the recorded first
+   * expiration is the max offset, then perform the safe fallback of checking
+   * all cookies.
+   */
+  if(now < cookies->next_expiration &&
+      cookies->next_expiration != CURL_OFF_T_MAX)
+    return;
+  else
+    cookies->next_expiration = CURL_OFF_T_MAX;
+
   for(i = 0; i < COOKIE_HASH_SIZE; i++) {
     struct Cookie *pv = NULL;
     co = cookies->cookies[i];
@@ -421,6 +411,12 @@ static void remove_expired(struct CookieInfo *cookies)
         freecookie(co);
       }
       else {
+        /*
+         * If this cookie has an expiration timestamp earlier than what we've
+         * seen so far then record it for the next round of expirations.
+         */
+        if(co->expires && co->expires < cookies->next_expiration)
+          cookies->next_expiration = co->expires;
         pv = co;
       }
       co = nx;
@@ -524,7 +520,7 @@ Curl_cookie_add(struct Curl_easy *data,
         if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) ||
            ((nlen + len) > MAX_NAME)) {
           freecookie(co);
-          infof(data, "oversized cookie dropped, name/val %zu + %zu bytes\n",
+          infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
                 nlen, len);
           return NULL;
         }
@@ -645,7 +641,7 @@ Curl_cookie_add(struct Curl_easy *data,
             domain = ":";
 #endif
 
-          is_ip = isip(domain ? domain : whatptr);
+          is_ip = Curl_host_is_ipnum(domain ? domain : whatptr);
 
           if(!domain
              || (is_ip && !strcmp(whatptr, domain))
@@ -665,7 +661,7 @@ Curl_cookie_add(struct Curl_easy *data,
              * not a domain to which the current host belongs. Mark as bad.
              */
             badcookie = TRUE;
-            infof(data, "skipped cookie with bad tailmatch domain: %s\n",
+            infof(data, "skipped cookie with bad tailmatch domain: %s",
                   whatptr);
           }
         }
@@ -996,7 +992,7 @@ Curl_cookie_add(struct Curl_easy *data,
    * must also check that the data handle isn't NULL since the psl code will
    * dereference it.
    */
-  if(data && (domain && co->domain && !isip(co->domain))) {
+  if(data && (domain && co->domain && !Curl_host_is_ipnum(co->domain))) {
     const psl_ctx_t *psl = Curl_psl_use(data);
     int acceptable;
 
@@ -1009,7 +1005,7 @@ Curl_cookie_add(struct Curl_easy *data,
 
     if(!acceptable) {
       infof(data, "cookie '%s' dropped, domain '%s' must not "
-                  "set cookies for '%s'\n", co->name, domain, co->domain);
+                  "set cookies for '%s'", co->name, domain, co->domain);
       freecookie(co);
       return NULL;
     }
@@ -1121,7 +1117,7 @@ Curl_cookie_add(struct Curl_easy *data,
   if(c->running)
     /* Only show this when NOT reading the cookies from a file */
     infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
-          "expire %" CURL_FORMAT_CURL_OFF_T "\n",
+          "expire %" CURL_FORMAT_CURL_OFF_T,
           replace_old?"Replaced":"Added", co->name, co->value,
           co->domain, co->path, co->expires);
 
@@ -1134,6 +1130,13 @@ Curl_cookie_add(struct Curl_easy *data,
     c->numcookies++; /* one more cookie in the jar */
   }
 
+  /*
+   * Now that we've added a new cookie to the jar, update the expiration
+   * tracker in case it is the next one to expire.
+   */
+  if(co->expires && (co->expires < c->next_expiration))
+    c->next_expiration = co->expires;
+
   return co;
 }
 
@@ -1169,6 +1172,11 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
     c->filename = strdup(file?file:"none"); /* copy the name just in case */
     if(!c->filename)
       goto fail; /* failed to get memory */
+    /*
+     * Initialize the next_expiration time to signal that we don't have enough
+     * information yet.
+     */
+    c->next_expiration = CURL_OFF_T_MAX;
   }
   else {
     /* we got an already existing one, use that */
@@ -1215,7 +1223,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
 
     /*
      * Remove expired cookies from the hash. We must make sure to run this
-     * after reading the file, and not not on every cookie.
+     * after reading the file, and not on every cookie.
      */
     remove_expired(c);
 
@@ -1247,7 +1255,8 @@ fail:
  *
  * Helper function to sort cookies such that the longest path gets before the
  * shorter path. Path, domain and name lengths are considered in that order,
- * with tge creationtime as the tiebreaker.
+ * with the creationtime as the tiebreaker. The creationtime is guaranteed to
+ * be unique per cookie, so we know we will get an ordering at that point.
  */
 static int cookie_sort(const void *p1, const void *p2)
 {
@@ -1355,7 +1364,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
   remove_expired(c);
 
   /* check if host is an IP(v4|v6) address */
-  is_ip = isip(host);
+  is_ip = Curl_host_is_ipnum(host);
 
   co = c->cookies[myhash];
 
@@ -1734,7 +1743,7 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup)
     /* if we have a destination file for all the cookies to get dumped to */
     res = cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR]);
     if(res)
-      infof(data, "WARNING: failed to save cookies in %s: %s\n",
+      infof(data, "WARNING: failed to save cookies in %s: %s",
             data->set.str[STRING_COOKIEJAR], curl_easy_strerror(res));
   }
   else {
index 460bbb1..0ffe08e 100644 (file)
@@ -65,6 +65,7 @@ struct CookieInfo {
   bool running;    /* state info, for cookie adding information */
   bool newsession; /* new session, discard session cookies on load */
   int lastct;      /* last creation-time used in the jar */
+  curl_off_t next_expiration; /* the next time at which expiration happens */
 };
 
 /* This is the maximum line length we accept for a cookie line. RFC 2109
index 1d5067b..842fd7f 100644 (file)
 #  define in_addr_t unsigned long
 #endif
 
-#if defined(USE_UNIX_SOCKETS) && defined(WINAPI_FAMILY) && \
-    (WINAPI_FAMILY == WINAPI_FAMILY_APP)
-   /* Required for sockaddr_un type */
-#  include <afunix.h>
-#endif
-
 #include <stddef.h>
 
 #include "curl_addrinfo.h"
index 4fdc672..de03550 100644 (file)
 /* when building libcurl itself */
 #cmakedefine BUILDING_LIBCURL 1
 
-/* to disable cookies support */
+/* to disable alt-svc */
+#cmakedefine CURL_DISABLE_ALTSVC 1
+
+/* disables cookies support */
 #cmakedefine CURL_DISABLE_COOKIES 1
 
-/* to disable cryptographic authentication */
+/* disables cryptographic authentication */
 #cmakedefine CURL_DISABLE_CRYPTO_AUTH 1
 
-/* to disable DICT */
+/* disables DICT */
 #cmakedefine CURL_DISABLE_DICT 1
 
-/* to disable FILE */
+/* disables DNS-over-HTTPS */
+#cmakedefine CURL_DISABLE_DOH 1
+
+/* disables FILE */
 #cmakedefine CURL_DISABLE_FILE 1
 
-/* to disable FTP */
+/* disables FTP */
 #cmakedefine CURL_DISABLE_FTP 1
 
-/* to disable GOPHER */
+/* disables GOPHER */
 #cmakedefine CURL_DISABLE_GOPHER 1
 
-/* to disable IMAP */
-#cmakedefine CURL_DISABLE_IMAP 1
+/* disables HSTS support */
+#cmakedefine CURL_DISABLE_HSTS 1
 
-/* to disable HTTP */
+/* disables HTTP */
 #cmakedefine CURL_DISABLE_HTTP 1
 
-/* to disable LDAP */
+/* disables IMAP */
+#cmakedefine CURL_DISABLE_IMAP 1
+
+/* disables LDAP */
 #cmakedefine CURL_DISABLE_LDAP 1
 
-/* to disable LDAPS */
+/* disables LDAPS */
 #cmakedefine CURL_DISABLE_LDAPS 1
 
-/* to disable MQTT */
+/* disables --libcurl option from the curl tool */
+#cmakedefine CURL_DISABLE_LIBCURL_OPTION 1
+
+/* disables MIME support */
+#cmakedefine CURL_DISABLE_MIME 1
+
+/* disables MQTT */
 #cmakedefine CURL_DISABLE_MQTT 1
 
-/* to disable POP3 */
+/* disables netrc parser */
+#cmakedefine CURL_DISABLE_NETRC 1
+
+/* disables NTLM support */
+#cmakedefine CURL_DISABLE_NTLM 1
+
+/* disables date parsing */
+#cmakedefine CURL_DISABLE_PARSEDATE 1
+
+/* disables POP3 */
 #cmakedefine CURL_DISABLE_POP3 1
 
-/* to disable proxies */
+/* disables built-in progress meter */
+#cmakedefine CURL_DISABLE_PROGRESS_METER 1
+
+/* disables proxies */
 #cmakedefine CURL_DISABLE_PROXY 1
 
-/* to disable RTSP */
+/* disables RTSP */
 #cmakedefine CURL_DISABLE_RTSP 1
 
-/* to disable SMB */
+/* disables SMB */
 #cmakedefine CURL_DISABLE_SMB 1
 
-/* to disable SMTP */
+/* disables SMTP */
 #cmakedefine CURL_DISABLE_SMTP 1
 
-/* to disable TELNET */
+/* disables use of socketpair for curl_multi_poll */
+#cmakedefine CURL_DISABLE_SOCKETPAIR 1
+
+/* disables TELNET */
 #cmakedefine CURL_DISABLE_TELNET 1
 
-/* to disable TFTP */
+/* disables TFTP */
 #cmakedefine CURL_DISABLE_TFTP 1
 
-/* to disable verbose strings */
+/* disables verbose strings */
 #cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1
 
 /* to make a symbol visible */
 /* Define if you want to enable IPv6 support */
 #cmakedefine ENABLE_IPV6 1
 
-/* 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 `CRYPTO_cleanup_all_ex_data' function. */
 #cmakedefine HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
 
-/* Define to 1 if you have the <crypto.h> header file. */
-#cmakedefine HAVE_CRYPTO_H 1
-
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #cmakedefine HAVE_DLFCN_H 1
 
 /* Define to 1 if you have the <errno.h> header file. */
 #cmakedefine HAVE_ERRNO_H 1
 
-/* Define to 1 if you have the <err.h> 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 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 the `getppid' function. */
 #cmakedefine HAVE_GETPPID 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 `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 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 <libssh2.h> header file. */
 #cmakedefine HAVE_LIBSSH2_H 1
 
 /* Define to 1 if you have the recvfrom function. */
 #cmakedefine HAVE_RECVFROM 1
 
-/* Define to 1 if you have the <rsa.h> 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 a working setsockopt SO_NONBLOCK function. */
 #cmakedefine HAVE_SETSOCKOPT_SO_NONBLOCK 1
 
-/* Define to 1 if you have the <sgtty.h> 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 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
 
@@ -994,9 +958,6 @@ ${SIZEOF_TIME_T_CODE}
 /* if Unix domain sockets are enabled  */
 #cmakedefine USE_UNIX_SOCKETS
 
-/* to disable alt-svc */
-#cmakedefine CURL_DISABLE_ALTSVC 1
-
 /* to enable SSPI support */
 #cmakedefine USE_WINDOWS_SSPI 1
 
index b6f107e..ecde74b 100644 (file)
@@ -80,45 +80,3 @@ unsigned short Curl_read16_be(const unsigned char *buf)
   return (unsigned short)(((unsigned short)buf[0] << 8) |
                           ((unsigned short)buf[1]));
 }
-
-#if (SIZEOF_CURL_OFF_T > 4)
-/*
- * write32_le()
- *
- * This function converts a 32-bit integer from the native endian format,
- * to little endian format ready for sending down the wire.
- *
- * Parameters:
- *
- * value    [in]     - The 32-bit integer value.
- * buffer   [in]     - A pointer to the output buffer.
- */
-static void write32_le(const int value, unsigned char *buffer)
-{
-  buffer[0] = (char)(value & 0x000000FF);
-  buffer[1] = (char)((value & 0x0000FF00) >> 8);
-  buffer[2] = (char)((value & 0x00FF0000) >> 16);
-  buffer[3] = (char)((value & 0xFF000000) >> 24);
-}
-
-/*
- * Curl_write64_le()
- *
- * This function converts a 64-bit integer from the native endian format,
- * to little endian format ready for sending down the wire.
- *
- * Parameters:
- *
- * value    [in]     - The 64-bit integer value.
- * buffer   [in]     - A pointer to the output buffer.
- */
-#if defined(HAVE_LONGLONG)
-void Curl_write64_le(const long long value, unsigned char *buffer)
-#else
-void Curl_write64_le(const __int64 value, unsigned char *buffer)
-#endif
-{
-  write32_le((int)value, buffer);
-  write32_le((int)(value >> 32), buffer + 4);
-}
-#endif /* SIZEOF_CURL_OFF_T > 4 */
index acaaa1c..5810dad 100644 (file)
@@ -59,7 +59,7 @@ OM_uint32 Curl_gss_init_sec_context(
     req_flags |= GSS_C_DELEG_POLICY_FLAG;
 #else
     infof(data, "warning: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not "
-        "compiled in\n");
+        "compiled in");
 #endif
   }
 
@@ -130,7 +130,7 @@ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
 
   display_gss_error(minor, GSS_C_MECH_CODE, buf, len);
 
-  infof(data, "%s%s\n", prefix, buf);
+  infof(data, "%s%s", prefix, buf);
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
   (void)data;
   (void)prefix;
index 16418be..e9d2a8c 100644 (file)
@@ -102,14 +102,16 @@ int curlx_win32_open(const char *filename, int oflag, ...)
   va_end(param);
 
 #ifdef _UNICODE
-  if(filename_w)
+  if(filename_w) {
     result = _wopen(filename_w, oflag, pmode);
-  free(filename_w);
-  if(result != -1)
-    return result;
-#endif
-
+    free(filename_w);
+  }
+  else
+    errno = EINVAL;
+  return result;
+#else
   return (_open)(filename, oflag, pmode);
+#endif
 }
 
 FILE *curlx_win32_fopen(const char *filename, const char *mode)
@@ -120,19 +122,20 @@ FILE *curlx_win32_fopen(const char *filename, const char *mode)
   wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode);
   if(filename_w && mode_w)
     result = _wfopen(filename_w, mode_w);
+  else
+    errno = EINVAL;
   free(filename_w);
   free(mode_w);
-  if(result)
-    return result;
-#endif
-
+  return result;
+#else
   return (fopen)(filename, mode);
+#endif
 }
 
 int curlx_win32_stat(const char *path, struct_stat *buffer)
 {
-  int result = -1;
 #ifdef _UNICODE
+  int result = -1;
   wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
   if(path_w) {
 #if defined(USE_WIN32_SMALL_FILES)
@@ -141,31 +144,34 @@ int curlx_win32_stat(const char *path, struct_stat *buffer)
     result = _wstati64(path_w, buffer);
 #endif
     free(path_w);
-    if(result != -1)
-      return result;
   }
-#endif /* _UNICODE */
-
+  else
+    errno = EINVAL;
+  return result;
+#else
 #if defined(USE_WIN32_SMALL_FILES)
-  result = _stat(path, buffer);
+  return _stat(path, buffer);
 #else
-  result = _stati64(path, buffer);
+  return _stati64(path, buffer);
+#endif
 #endif
-  return result;
 }
 
 int curlx_win32_access(const char *path, int mode)
 {
 #if defined(_UNICODE)
+  int result = -1;
   wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
   if(path_w) {
-    int result = _waccess(path_w, mode);
+    result = _waccess(path_w, mode);
     free(path_w);
-    if(result != -1)
-      return result;
   }
-#endif /* _UNICODE */
+  else
+    errno = EINVAL;
+  return result;
+#else
   return _access(path, mode);
+#endif
 }
 
 #endif /* USE_WIN32_LARGE_FILES || USE_WIN32_SMALL_FILES */
index 89d4ec8..749b44e 100644 (file)
@@ -86,7 +86,6 @@
 #elif defined(USE_MBEDTLS)
 
 #  include <mbedtls/des.h>
-#  include "curl_md4.h"
 
 #elif defined(USE_SECTRANSP)
 
@@ -498,17 +497,14 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
    * network encoding not the host encoding.
    */
   result = Curl_convert_to_network(data, (char *)pw, len * 2);
-  if(result)
-    return result;
-
-  /* Create NT hashed password. */
-  Curl_md4it(ntbuffer, pw, 2 * len);
-
-  memset(ntbuffer + 16, 0, 21 - 16);
-
+  if(!result) {
+    /* Create NT hashed password. */
+    Curl_md4it(ntbuffer, pw, 2 * len);
+    memset(ntbuffer + 16, 0, 21 - 16);
+  }
   free(pw);
 
-  return CURLE_OK;
+  return result;
 }
 
 #if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI)
index 9af79fd..5a3bc3c 100644 (file)
@@ -355,17 +355,17 @@ CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
   }
   else {
     if(*state == NTLMSTATE_LAST) {
-      infof(data, "NTLM auth restarted\n");
+      infof(data, "NTLM auth restarted");
       Curl_http_auth_cleanup_ntlm_wb(conn);
     }
     else if(*state == NTLMSTATE_TYPE3) {
-      infof(data, "NTLM handshake rejected\n");
+      infof(data, "NTLM handshake rejected");
       Curl_http_auth_cleanup_ntlm_wb(conn);
       *state = NTLMSTATE_NONE;
       return CURLE_REMOTE_ACCESS_DENIED;
     }
     else if(*state >= NTLMSTATE_TYPE1) {
-      infof(data, "NTLM handshake failure (internal error)\n");
+      infof(data, "NTLM handshake failure (internal error)");
       return CURLE_REMOTE_ACCESS_DENIED;
     }
 
@@ -426,7 +426,8 @@ CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
     /* Use Samba's 'winbind' daemon to support NTLM authentication,
      * by delegating the NTLM challenge/response protocol to a helper
      * in ntlm_auth.
-     * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
+     * https://web.archive.org/web/20190925164737
+     * /devel.squid-cache.org/ntlm/squid_helper_protocol.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
index f7fb7c0..24bdb30 100644 (file)
@@ -53,14 +53,14 @@ CURLcode Curl_range(struct Curl_easy *data)
     if((to_t == CURL_OFFT_INVAL) && !from_t) {
       /* X - */
       data->state.resume_from = from;
-      DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n",
+      DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file",
                    from));
     }
     else if((from_t == CURL_OFFT_INVAL) && !to_t) {
       /* -Y */
       data->req.maxdownload = to;
       data->state.resume_from = -to;
-      DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n",
+      DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes",
                    to));
     }
     else {
@@ -78,12 +78,12 @@ CURLcode Curl_range(struct Curl_easy *data)
       data->req.maxdownload = totalsize + 1; /* include last byte */
       data->state.resume_from = from;
       DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T
-                   " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
+                   " getting %" CURL_FORMAT_CURL_OFF_T " bytes",
                    from, data->req.maxdownload));
     }
     DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T
                  " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
-                 CURL_FORMAT_CURL_OFF_T " bytes\n",
+                 CURL_FORMAT_CURL_OFF_T " bytes",
                  from, to, data->req.maxdownload));
   }
   else
index a4d1059..4a24887 100644 (file)
@@ -234,7 +234,7 @@ static void state(struct SASL *sasl, struct Curl_easy *data,
   };
 
   if(sasl->state != newstate)
-    infof(data, "SASL %p state change from %s to %s\n",
+    infof(data, "SASL %p state change from %s to %s",
           (void *)sasl, names[sasl->state], names[newstate]);
 #else
   (void) data;
@@ -630,7 +630,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
       }
       else
         /* Decode the security challenge and create the response message */
-        result = Curl_auth_create_gssapi_security_message(data, &serverdata,
+        result = Curl_auth_create_gssapi_security_message(data,
+                                                          conn->sasl_authzid,
+                                                          &serverdata,
                                                           &conn->krb5,
                                                           &resp);
     }
@@ -639,7 +641,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
     /* Decode the security challenge and create the response message */
     result = get_server_message(sasl, data, &serverdata);
     if(!result)
-      result = Curl_auth_create_gssapi_security_message(data, &serverdata,
+      result = Curl_auth_create_gssapi_security_message(data,
+                                                        conn->sasl_authzid,
+                                                        &serverdata,
                                                         &conn->krb5,
                                                         &resp);
     break;
index 2d13a40..554dcc1 100644 (file)
  */
 
 #ifdef HTTP_ONLY
-#  ifndef CURL_DISABLE_TFTP
-#    define CURL_DISABLE_TFTP
+#  ifndef CURL_DISABLE_DICT
+#    define CURL_DISABLE_DICT
+#  endif
+#  ifndef CURL_DISABLE_FILE
+#    define CURL_DISABLE_FILE
 #  endif
 #  ifndef CURL_DISABLE_FTP
 #    define CURL_DISABLE_FTP
 #  endif
+#  ifndef CURL_DISABLE_GOPHER
+#    define CURL_DISABLE_GOPHER
+#  endif
+#  ifndef CURL_DISABLE_IMAP
+#    define CURL_DISABLE_IMAP
+#  endif
 #  ifndef CURL_DISABLE_LDAP
 #    define CURL_DISABLE_LDAP
 #  endif
-#  ifndef CURL_DISABLE_TELNET
-#    define CURL_DISABLE_TELNET
+#  ifndef CURL_DISABLE_LDAPS
+#    define CURL_DISABLE_LDAPS
 #  endif
-#  ifndef CURL_DISABLE_DICT
-#    define CURL_DISABLE_DICT
+#  ifndef CURL_DISABLE_MQTT
+#    define CURL_DISABLE_MQTT
 #  endif
-#  ifndef CURL_DISABLE_FILE
-#    define CURL_DISABLE_FILE
+#  ifndef CURL_DISABLE_POP3
+#    define CURL_DISABLE_POP3
 #  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
+#  ifndef CURL_DISABLE_SMB
+#    define CURL_DISABLE_SMB
 #  endif
 #  ifndef CURL_DISABLE_SMTP
 #    define CURL_DISABLE_SMTP
 #  endif
-#  ifndef CURL_DISABLE_GOPHER
-#    define CURL_DISABLE_GOPHER
+#  ifndef CURL_DISABLE_TELNET
+#    define CURL_DISABLE_TELNET
 #  endif
-#  ifndef CURL_DISABLE_SMB
-#    define CURL_DISABLE_SMB
+#  ifndef CURL_DISABLE_TFTP
+#    define CURL_DISABLE_TFTP
 #  endif
 #endif
 
 #endif
 #endif
 
+#ifndef SSIZE_T_MAX
+/* some limits.h headers have this defined, some don't */
+#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
+#define SSIZE_T_MAX 9223372036854775807
+#else
+#define SSIZE_T_MAX 2147483647
+#endif
+#endif
+
 /*
  * Arg 2 type for gethostname in case it hasn't been defined in config file.
  */
@@ -659,24 +674,16 @@ int netware_init(void);
 #endif
 
 /* Single point where USE_NTLM definition might be defined */
-#ifndef CURL_DISABLE_CRYPTO_AUTH
-#if defined(USE_OPENSSL) || defined(USE_MBEDTLS) ||                     \
-  defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) ||  \
-  defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) ||              \
-  (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT))
-
-#define USE_CURL_NTLM_CORE
-
-#  if defined(USE_MBEDTLS)
-/* Get definition of MBEDTLS_MD4_C */
-#  include <mbedtls/md4.h>
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(CURL_DISABLE_NTLM)
+#  if defined(USE_OPENSSL) || defined(USE_MBEDTLS) ||                       \
+      defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) ||  \
+      defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) ||              \
+      (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT))
+#    define USE_CURL_NTLM_CORE
+#  endif
+#  if defined(USE_CURL_NTLM_CORE) || defined(USE_WINDOWS_SSPI)
+#    define USE_NTLM
 #  endif
-
-#endif
-
-#if defined(USE_CURL_NTLM_CORE) || defined(USE_WINDOWS_SSPI)
-#define USE_NTLM
-#endif
 #endif
 
 #ifdef CURL_WANTS_CA_BUNDLE_ENV
@@ -834,4 +841,20 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
 #define ENABLE_QUIC
 #endif
 
+#if defined(USE_UNIX_SOCKETS) && defined(WIN32)
+#  if defined(__MINGW32__) && !defined(LUP_SECURE)
+     typedef u_short ADDRESS_FAMILY; /* Classic mingw, 11y+ old mingw-w64 */
+#  endif
+#  if !defined(UNIX_PATH_MAX)
+     /* Replicating logic present in afunix.h
+        (distributed with newer Windows 10 SDK versions only) */
+#    define UNIX_PATH_MAX 108
+     /* !checksrc! disable TYPEDEFSTRUCT 1 */
+     typedef struct sockaddr_un {
+       ADDRESS_FAMILY sun_family;
+       char sun_path[UNIX_PATH_MAX];
+     } SOCKADDR_UN, *PSOCKADDR_UN;
+#  endif
+#endif
+
 #endif /* HEADER_CURL_SETUP_H */
index 22d0a06..38018d2 100644 (file)
@@ -323,26 +323,6 @@ struct timeval {
 
 #include "curl_ctype.h"
 
-/*
- * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type.
- */
-
-#ifndef HAVE_SIG_ATOMIC_T
-typedef int sig_atomic_t;
-#define HAVE_SIG_ATOMIC_T
-#endif
-
-
-/*
- * Convenience SIG_ATOMIC_T definition
- */
-
-#ifdef HAVE_SIG_ATOMIC_T_VOLATILE
-#define SIG_ATOMIC_T static sig_atomic_t
-#else
-#define SIG_ATOMIC_T static volatile sig_atomic_t
-#endif
-
 
 /*
  * Macro used to include code only in debug builds.
index 625b057..5d53b8f 100644 (file)
@@ -216,7 +216,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
     }
 
     if(!word || (*word == (char)0)) {
-      infof(data, "lookup word is missing\n");
+      infof(data, "lookup word is missing");
       word = (char *)"default";
     }
     if(!database || (*database == (char)0)) {
@@ -267,7 +267,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
     }
 
     if(!word || (*word == (char)0)) {
-      infof(data, "lookup word is missing\n");
+      infof(data, "lookup word is missing");
       word = (char *)"default";
     }
     if(!database || (*database == (char)0)) {
index 36f8cd5..de0c902 100644 (file)
@@ -186,19 +186,19 @@ doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
   return realsize;
 }
 
-/* called from multi.c when this DOH transfer is complete */
+/* called from multi.c when this DoH transfer is complete */
 static int doh_done(struct Curl_easy *doh, CURLcode result)
 {
   struct Curl_easy *data = doh->set.dohfor;
   struct dohdata *dohp = data->req.doh;
-  /* so one of the DOH request done for the 'data' transfer is now complete! */
+  /* so one of the DoH request done for the 'data' transfer is now complete! */
   dohp->pending--;
-  infof(data, "a DOH request is completed, %u to go\n", dohp->pending);
+  infof(data, "a DoH request is completed, %u to go", dohp->pending);
   if(result)
-    infof(data, "DOH request %s\n", curl_easy_strerror(result));
+    infof(data, "DoH request %s", curl_easy_strerror(result));
 
   if(!dohp->pending) {
-    /* DOH completed */
+    /* DoH completed */
     curl_slist_free_all(dohp->headers);
     dohp->headers = NULL;
     Curl_expire(data, 0, EXPIRE_RUN_NOW);
@@ -228,7 +228,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
   DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer),
                          &p->dohlen);
   if(d) {
-    failf(data, "Failed to encode DOH packet [%d]", d);
+    failf(data, "Failed to encode DoH packet [%d]", d);
     return CURLE_OUT_OF_MEMORY;
   }
 
@@ -302,7 +302,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
     /* Inherit *some* SSL options from the user's transfer. This is a
        best-guess as to which options are needed for compatibility. #3661
 
-       Note DOH does not inherit the user's proxy server so proxy SSL settings
+       Note DoH does not inherit the user's proxy server so proxy SSL settings
        have no effect and are not inherited. If that changes then two new
        options should be added to check doh proxy insecure separately,
        CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER.
@@ -359,17 +359,17 @@ static CURLcode dohprobe(struct Curl_easy *data,
         (data->set.ssl.auto_client_cert ?
          CURLSSLOPT_AUTO_CLIENT_CERT : 0);
 
-      curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask);
+      (void)curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask);
     }
 
     doh->set.fmultidone = doh_done;
     doh->set.dohfor = data; /* identify for which transfer this is done */
     p->easy = doh;
 
-    /* DOH private_data must be null because the user must have a way to
-       distinguish their transfer's handle from DOH handles in user
+    /* DoH private_data must be null because the user must have a way to
+       distinguish their transfer's handle from DoH handles in user
        callbacks (ie SSL CTX callback). */
-    DEBUGASSERT(!data->set.private_data);
+    DEBUGASSERT(!doh->set.private_data);
 
     if(curl_multi_add_handle(multi, doh))
       goto error;
@@ -386,7 +386,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
 }
 
 /*
- * Curl_doh() resolves a name using DOH. It resolves a name and returns a
+ * Curl_doh() resolves a name using DoH. It resolves a name and returns a
  * 'Curl_addrinfo *' with the address information.
  */
 
@@ -420,7 +420,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
   if(!dohp->headers)
     goto error;
 
-  /* create IPv4 DOH request */
+  /* create IPv4 DoH request */
   result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
                     DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
                     data->multi, dohp->headers);
@@ -429,7 +429,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
   dohp->pending++;
 
   if(Curl_ipv6works(data)) {
-    /* create IPv6 DOH request */
+    /* create IPv6 DoH request */
     result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
                       DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
                       data->multi, dohp->headers);
@@ -764,11 +764,11 @@ static void showdoh(struct Curl_easy *data,
                     const struct dohentry *d)
 {
   int i;
-  infof(data, "TTL: %u seconds\n", d->ttl);
+  infof(data, "TTL: %u seconds", d->ttl);
   for(i = 0; i < d->numaddr; i++) {
     const struct dohaddr *a = &d->addr[i];
     if(a->type == DNS_TYPE_A) {
-      infof(data, "DOH A: %u.%u.%u.%u\n",
+      infof(data, "DoH A: %u.%u.%u.%u",
             a->ip.v4[0], a->ip.v4[1],
             a->ip.v4[2], a->ip.v4[3]);
     }
@@ -777,7 +777,7 @@ static void showdoh(struct Curl_easy *data,
       char buffer[128];
       char *ptr;
       size_t len;
-      msnprintf(buffer, 128, "DOH AAAA: ");
+      msnprintf(buffer, 128, "DoH AAAA: ");
       ptr = &buffer[10];
       len = 118;
       for(j = 0; j < 16; j += 2) {
@@ -788,11 +788,11 @@ static void showdoh(struct Curl_easy *data,
         len -= l;
         ptr += l;
       }
-      infof(data, "%s\n", buffer);
+      infof(data, "%s", buffer);
     }
   }
   for(i = 0; i < d->numcname; i++) {
-    infof(data, "CNAME: %s\n", Curl_dyn_ptr(&d->cname[i]));
+    infof(data, "CNAME: %s", Curl_dyn_ptr(&d->cname[i]));
   }
 }
 #else
@@ -803,7 +803,7 @@ static void showdoh(struct Curl_easy *data,
  * doh2ai()
  *
  * This function returns a pointer to the first element of a newly allocated
- * Curl_addrinfo struct linked list filled with the data from a set of DOH
+ * Curl_addrinfo struct linked list filled with the data from a set of DoH
  * lookups.  Curl_addrinfo is meant to work like the addrinfo struct does for
  * a IPv6 stack, but usable also for IPv4, all hosts and environments.
  *
@@ -931,7 +931,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
 
   if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
      !dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
-    failf(data, "Could not DOH-resolve: %s", data->state.async.hostname);
+    failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
     return data->conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
       CURLE_COULDNT_RESOLVE_HOST;
   }
@@ -941,7 +941,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
     };
     struct dohentry de;
     int slot;
-    /* remove DOH handles from multi handle and close them */
+    /* remove DoH handles from multi handle and close them */
     for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
       curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
       Curl_close(&dohp->probe[slot].easy);
@@ -958,7 +958,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
                             &de);
       Curl_dyn_free(&p->serverdoh);
       if(rc[slot]) {
-        infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc[slot]),
+        infof(data, "DoH: %s type %s for %s", doh_strerror(rc[slot]),
               type2name(p->dnstype), dohp->host);
       }
     } /* next slot */
@@ -969,7 +969,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
       struct Curl_dns_entry *dns;
       struct Curl_addrinfo *ai;
 
-      infof(data, "DOH Host name: %s\n", dohp->host);
+      infof(data, "DoH Host name: %s", dohp->host);
       showdoh(data, &de);
 
       ai = doh2ai(&de, dohp->host, dohp->port);
@@ -1007,7 +1007,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
 
   } /* !dohp->pending */
 
-  /* else wait for pending DOH transactions to complete */
+  /* else wait for pending DoH transactions to complete */
   return CURLE_OK;
 }
 
index b3584d1..70e96e0 100644 (file)
@@ -101,7 +101,7 @@ void de_init(struct dohentry *d);
 void de_cleanup(struct dohentry *d);
 #endif
 
-#else /* if DOH is disabled */
+#else /* if DoH is disabled */
 #define Curl_doh(a,b,c,d) NULL
 #define Curl_doh_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
 #endif
index 530b7c7..2aca938 100644 (file)
@@ -117,7 +117,7 @@ curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
 curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
 curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
 #if defined(WIN32) && defined(UNICODE)
-curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
+curl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup;
 #endif
 
 #if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
@@ -417,13 +417,13 @@ static int events_socket(struct Curl_easy *easy,      /* easy handle */
           ev->list = nxt;
         free(m);
         m = nxt;
-        infof(easy, "socket cb: socket %d REMOVED\n", s);
+        infof(easy, "socket cb: socket %d REMOVED", s);
       }
       else {
         /* The socket 's' is already being monitored, update the activity
            mask. Convert from libcurl bitmask to the poll one. */
         m->socket.events = socketcb2poll(what);
-        infof(easy, "socket cb: socket %d UPDATED as %s%s\n", s,
+        infof(easy, "socket cb: socket %d UPDATED as %s%s", s,
               (what&CURL_POLL_IN)?"IN":"",
               (what&CURL_POLL_OUT)?"OUT":"");
       }
@@ -447,7 +447,7 @@ static int events_socket(struct Curl_easy *easy,      /* easy handle */
         m->socket.events = socketcb2poll(what);
         m->socket.revents = 0;
         ev->list = m;
-        infof(easy, "socket cb: socket %d ADDED as %s%s\n", s,
+        infof(easy, "socket cb: socket %d ADDED as %s%s", s,
               (what&CURL_POLL_IN)?"IN":"",
               (what&CURL_POLL_OUT)?"OUT":"");
       }
@@ -532,7 +532,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)",
                 fds[i].fd);
           mcode = curl_multi_socket_action(multi, fds[i].fd, act,
                                            &ev->running_handles);
@@ -1027,7 +1027,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
 
   if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) {
     /* Not changing any pause state, return */
-    DEBUGF(infof(data, "pause: no change, early return\n"));
+    DEBUGF(infof(data, "pause: no change, early return"));
     return CURLE_OK;
   }
 
@@ -1213,9 +1213,16 @@ static int conn_upkeep(struct Curl_easy *data,
   /* Param is unused. */
   (void)param;
 
-  if(conn->handler->connection_check)
+  if(conn->handler->connection_check) {
+    /* briefly attach the connection to this transfer for the purpose of
+       checking it */
+    Curl_attach_connnection(data, conn);
+
     /* Do a protocol-specific keepalive check on the connection. */
     conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
+    /* detach the connection again */
+    Curl_detach_connnection(data);
+  }
 
   return 0; /* continue iteration */
 }
index 769f06a..ac7a000 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -865,8 +865,6 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
 
         if(post->flags & CURL_HTTPPOST_LARGE)
           clen = post->contentlen;
-        if(!clen)
-          clen = -1;
 
         if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
           if(!strcmp(file->contents, "-")) {
@@ -888,13 +886,21 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
         else if(post->flags & HTTPPOST_BUFFER)
           result = curl_mime_data(part, post->buffer,
                                   post->bufferlength? post->bufferlength: -1);
-        else if(post->flags & HTTPPOST_CALLBACK)
+        else if(post->flags & HTTPPOST_CALLBACK) {
           /* the contents should be read with the callback and the size is set
              with the contentslength */
+          if(!clen)
+            clen = -1;
           result = curl_mime_data_cb(part, clen,
                                      fread_func, NULL, NULL, post->userp);
+        }
         else {
-          result = curl_mime_data(part, post->contents, (ssize_t) clen);
+          size_t uclen;
+          if(!clen)
+            uclen = CURL_ZERO_TERMINATED;
+          else
+            uclen = (size_t)clen;
+          result = curl_mime_data(part, post->contents, uclen);
 #ifdef CURL_DOES_CONVERSIONS
           /* Convert textual contents now. */
           if(!result && data && part->datasize)
index 425b0af..cad584f 100644 (file)
@@ -289,7 +289,7 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
     failf(data, "Error accept()ing server connect");
     return CURLE_FTP_PORT_FAILED;
   }
-  infof(data, "Connection accepted from server\n");
+  infof(data, "Connection accepted from server");
   /* 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;
@@ -380,7 +380,7 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
   *received = FALSE;
 
   timeout_ms = ftp_timeleft_accept(data);
-  infof(data, "Checking for server connect\n");
+  infof(data, "Checking for server connect");
   if(timeout_ms < 0) {
     /* if a timeout was already reached, bail out */
     failf(data, "Accept timeout occurred while waiting server connect");
@@ -390,7 +390,7 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
   /* 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");
+    infof(data, "There is negative response in cache while serv connect");
     (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
     return CURLE_FTP_ACCEPT_FAILED;
   }
@@ -408,11 +408,11 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
   default:
 
     if(result & CURL_CSELECT_IN2) {
-      infof(data, "Ready to accept data connection from server\n");
+      infof(data, "Ready to accept data connection from server");
       *received = TRUE;
     }
     else if(result & CURL_CSELECT_IN) {
-      infof(data, "Ctrl conn has data while waiting for data conn\n");
+      infof(data, "Ctrl conn has data while waiting for data conn");
       (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
 
       if(ftpcode/100 > 3)
@@ -444,7 +444,7 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
   if(conn->bits.ftp_use_data_ssl) {
     /* 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");
+    infof(data, "Doing the SSL/TLS handshake on the data stream");
     result = Curl_ssl_connect(data, conn, SECONDARYSOCKET);
     if(result)
       return result;
@@ -487,7 +487,7 @@ static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
   CURLcode result = CURLE_OK;
 
   *connected = FALSE;
-  infof(data, "Preparing for accepting server on data port\n");
+  infof(data, "Preparing for accepting server on data port");
 
   /* Save the time we start accepting server connect */
   Curl_pgrsTime(data, TIMER_STARTACCEPT);
@@ -592,7 +592,7 @@ static CURLcode ftp_readresp(struct Curl_easy *data,
      * 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");
+    infof(data, "We got a 421 - timeout!");
     state(data, FTP_STOP);
     return CURLE_OPERATION_TIMEDOUT;
   }
@@ -768,7 +768,7 @@ static void _state(struct Curl_easy *data,
   (void) lineno;
 #else
   if(ftpc->state != newstate)
-    infof(data, "FTP %p (line %d) state change from %s to %s\n",
+    infof(data, "FTP %p (line %d) state change from %s to %s",
           (void *)ftpc, lineno, ftp_state_names[ftpc->state],
           ftp_state_names[newstate]);
 #endif
@@ -1139,7 +1139,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
         /* 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,
+        infof(data, "bind(port=%hu) on non-local address failed: %s", port,
               Curl_strerror(error, buffer, sizeof(buffer)));
 
         sslen = sizeof(ss);
@@ -1341,7 +1341,7 @@ static CURLcode ftp_state_use_pasv(struct Curl_easy *data,
   if(!result) {
     ftpc->count1 = modeoff;
     state(data, FTP_PASV);
-    infof(data, "Connect data stream passively\n");
+    infof(data, "Connect data stream passively");
   }
   return result;
 }
@@ -1648,7 +1648,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
       data->state.infilesize -= data->state.resume_from;
 
       if(data->state.infilesize <= 0) {
-        infof(data, "File already completely uploaded\n");
+        infof(data, "File already completely uploaded");
 
         /* no data to transfer */
         Curl_setup_transfer(data, -1, -1, FALSE, -1);
@@ -1802,7 +1802,7 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data,
     return CURLE_WEIRD_SERVER_REPLY;
   }
 
-  infof(data, "Failed EPSV attempt. Disabling EPSV\n");
+  infof(data, "Failed EPSV attempt. Disabling EPSV");
   /* disable it for next transfer */
   conn->bits.ftp_use_epsv = FALSE;
   data->state.errorbuf = FALSE; /* allow error message to get
@@ -1921,7 +1921,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
     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 %u.%u.%u.%u for data connection, re-use %s instead\n",
+      infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead",
             ip[0], ip[1], ip[2], ip[3],
             conn->host.name);
       ftpc->newhost = strdup(control_address(conn));
@@ -2044,7 +2044,7 @@ static CURLcode ftp_state_port_resp(struct Curl_easy *data,
     /* the command failed */
 
     if(EPRT == fcmd) {
-      infof(data, "disabling EPRT usage\n");
+      infof(data, "disabling EPRT usage");
       conn->bits.ftp_use_eprt = FALSE;
     }
     fcmd++;
@@ -2058,7 +2058,7 @@ static CURLcode ftp_state_port_resp(struct Curl_easy *data,
       result = ftp_state_use_port(data, fcmd);
   }
   else {
-    infof(data, "Connect data stream actively\n");
+    infof(data, "Connect data stream actively");
     state(data, FTP_STOP); /* end of DO phase */
     result = ftp_dophase_done(data, FALSE);
   }
@@ -2128,7 +2128,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
     }
     break;
   default:
-    infof(data, "unsupported MDTM reply format\n");
+    infof(data, "unsupported MDTM reply format");
     break;
   case 550: /* "No such file or directory" */
     failf(data, "Given file does not exist");
@@ -2142,7 +2142,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
       case CURL_TIMECOND_IFMODSINCE:
       default:
         if(data->info.filetime <= data->set.timevalue) {
-          infof(data, "The requested document is not new enough\n");
+          infof(data, "The requested document is not new enough");
           ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
           data->info.timecond = TRUE;
           state(data, FTP_STOP);
@@ -2151,7 +2151,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
         break;
       case CURL_TIMECOND_IFUNMODSINCE:
         if(data->info.filetime > data->set.timevalue) {
-          infof(data, "The requested document is not old enough\n");
+          infof(data, "The requested document is not old enough");
           ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
           data->info.timecond = TRUE;
           state(data, FTP_STOP);
@@ -2161,7 +2161,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
       } /* switch */
     }
     else {
-      infof(data, "Skipping time comparison\n");
+      infof(data, "Skipping time comparison");
     }
   }
 
@@ -2186,7 +2186,7 @@ static CURLcode ftp_state_type_resp(struct Curl_easy *data,
     return CURLE_FTP_COULDNT_SET_TYPE;
   }
   if(ftpcode != 200)
-    infof(data, "Got a %03d response code instead of the assumed 200\n",
+    infof(data, "Got a %03d response code instead of the assumed 200",
           ftpcode);
 
   if(instate == FTP_TYPE)
@@ -2219,7 +2219,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
     /* 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");
+      infof(data, "ftp server doesn't support SIZE");
       /* 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
@@ -2256,7 +2256,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
     if(ftp->downloadsize == 0) {
       /* no data to transfer */
       Curl_setup_transfer(data, -1, -1, FALSE, -1);
-      infof(data, "File already completely downloaded\n");
+      infof(data, "File already completely downloaded");
 
       /* Set ->transfer so that we won't get any error in ftp_done()
        * because we didn't transfer the any file */
@@ -2267,7 +2267,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
 
     /* Set resume file transfer offset */
     infof(data, "Instructs server to resume from offset %"
-          CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
+          CURL_FORMAT_CURL_OFF_T, data->state.resume_from);
 
     result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
                            data->state.resume_from);
@@ -2413,7 +2413,7 @@ static CURLcode ftp_state_stor_resp(struct Curl_easy *data,
 
     if(!connected) {
       struct ftp_conn *ftpc = &conn->proto.ftpc;
-      infof(data, "Data conn was not available immediately\n");
+      infof(data, "Data conn was not available immediately");
       ftpc->wait_data_conn = TRUE;
     }
 
@@ -2506,11 +2506,11 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
     else if((instate != FTP_LIST) && (data->state.prefer_ascii))
       size = -1; /* kludge for servers that understate ASCII mode file size */
 
-    infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
+    infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T,
           data->req.maxdownload);
 
     if(instate != FTP_LIST)
-      infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
+      infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T,
             size);
 
     /* FTP download: */
@@ -2526,7 +2526,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
 
       if(!connected) {
         struct ftp_conn *ftpc = &conn->proto.ftpc;
-        infof(data, "Data conn was not available immediately\n");
+        infof(data, "Data conn was not available immediately");
         state(data, FTP_STOP);
         ftpc->wait_data_conn = TRUE;
       }
@@ -2681,9 +2681,12 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
     /* 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(data, ftpcode, ftpc->state);
+      if(ftpcode == 230) {
+        /* 230 User logged in - already! Take as 220 if TLS required. */
+        if(data->set.use_ssl <= CURLUSESSL_TRY ||
+           conn->bits.ftp_use_control_ssl)
+          return ftp_state_user_resp(data, ftpcode, ftpc->state);
+      }
       else if(ftpcode != 220) {
         failf(data, "Got a %03d ftp-server response when 220 was expected",
               ftpcode);
@@ -2702,9 +2705,9 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
         Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
 
         if(Curl_sec_login(data, conn))
-          infof(data, "Logging in with password in cleartext!\n");
+          infof(data, "Logging in with password in cleartext!");
         else
-          infof(data, "Authentication successful\n");
+          infof(data, "Authentication successful");
       }
 #endif
 
@@ -2740,6 +2743,9 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
     case FTP_AUTH:
       /* we have gotten the response to a previous AUTH command */
 
+      if(pp->cache_size)
+        return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */
+
       /* RFC2228 (page 5) says:
        *
        * If the server is willing to accept the named security mechanism,
@@ -2895,7 +2901,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
             }
             Curl_safefree(ftpc->entrypath);
             ftpc->entrypath = dir; /* remember this */
-            infof(data, "Entry path is '%s'\n", ftpc->entrypath);
+            infof(data, "Entry path is '%s'", ftpc->entrypath);
             /* also save it where getinfo can access it: */
             data->state.most_recent_ftp_entrypath = ftpc->entrypath;
             state(data, FTP_SYST);
@@ -2904,18 +2910,18 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
 
           Curl_safefree(ftpc->entrypath);
           ftpc->entrypath = dir; /* remember this */
-          infof(data, "Entry path is '%s'\n", ftpc->entrypath);
+          infof(data, "Entry path is '%s'", 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");
+          infof(data, "Failed to figure out path");
         }
       }
       state(data, FTP_STOP); /* we are done with the CONNECT phase! */
-      DEBUGF(infof(data, "protocol connect phase DONE\n"));
+      DEBUGF(infof(data, "protocol connect phase DONE"));
       break;
 
     case FTP_SYST:
@@ -2962,7 +2968,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
       }
 
       state(data, FTP_STOP); /* we are done with the CONNECT phase! */
-      DEBUGF(infof(data, "protocol connect phase DONE\n"));
+      DEBUGF(infof(data, "protocol connect phase DONE"));
       break;
 
     case FTP_NAMEFMT:
@@ -2973,7 +2979,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
       }
 
       state(data, FTP_STOP); /* we are done with the CONNECT phase! */
-      DEBUGF(infof(data, "protocol connect phase DONE\n"));
+      DEBUGF(infof(data, "protocol connect phase DONE"));
       break;
 
     case FTP_QUOTE:
@@ -3272,7 +3278,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
     }
 
     if(ftpc->prevpath)
-      infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
+      infof(data, "Remembering we are in dir \"%s\"", ftpc->prevpath);
   }
 
   /* free the dir tree and file parts */
@@ -3338,7 +3344,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
     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");
+      infof(data, "partial download completed, closing connection");
       connclose(conn, "Partial download with no ability to check");
       return result;
     }
@@ -3529,7 +3535,7 @@ ftp_pasv_verbose(struct Curl_easy *data,
 {
   char buf[256];
   Curl_printable_address(ai, buf, sizeof(buf));
-  infof(data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
+  infof(data, "Connecting to %s (%s) port %d", newhost, buf, port);
 }
 #endif
 
@@ -3569,7 +3575,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
 
     /* Ready to do more? */
     if(connected) {
-      DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
+      DEBUGF(infof(data, "DO-MORE connected phase starts"));
     }
     else {
       if(result && (ftpc->count1 == 0)) {
@@ -3644,8 +3650,13 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
         return result;
 
       result = ftp_multi_statemach(data, &complete);
-      /* ftpc->wait_data_conn is always false here */
-      *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 */
@@ -3692,7 +3703,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
   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));
+    DEBUGF(infof(data, "DO-MORE phase ends with %d", (int)result));
   }
 
   return result;
@@ -3717,7 +3728,7 @@ CURLcode ftp_perform(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
 
-  DEBUGF(infof(data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts"));
 
   if(data->set.opt_no_body) {
     /* requested no body means no transfer... */
@@ -3737,10 +3748,10 @@ CURLcode ftp_perform(struct Curl_easy *data,
 
   *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
 
-  infof(data, "ftp_perform ends with SECONDARY: %d\n", *connected);
+  infof(data, "ftp_perform ends with SECONDARY: %d", *connected);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete1\n"));
+    DEBUGF(infof(data, "DO phase is complete1"));
   }
 
   return result;
@@ -3835,7 +3846,7 @@ static CURLcode init_wc_data(struct Curl_easy *data)
   /* let the writefunc callback know the transfer */
   data->set.out = data;
 
-  infof(data, "Wildcard - Parsing started\n");
+  infof(data, "Wildcard - Parsing started");
   return CURLE_OK;
 
   fail:
@@ -3902,7 +3913,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
       free(ftp->pathalloc);
       ftp->pathalloc = ftp->path = tmp_path;
 
-      infof(data, "Wildcard - START of \"%s\"\n", finfo->filename);
+      infof(data, "Wildcard - START of \"%s\"", finfo->filename);
       if(data->set.chunk_bgn) {
         long userresponse;
         Curl_set_in_callback(data, true);
@@ -3911,7 +3922,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
         Curl_set_in_callback(data, false);
         switch(userresponse) {
         case CURL_CHUNK_BGN_FUNC_SKIP:
-          infof(data, "Wildcard - \"%s\" skipped by user\n",
+          infof(data, "Wildcard - \"%s\" skipped by user",
                 finfo->filename);
           wildcard->state = CURLWC_SKIP;
           continue;
@@ -4234,7 +4245,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
         n -= ftpc->file?strlen(ftpc->file):0;
 
       if((strlen(oldPath) == n) && !strncmp(rawPath, oldPath, n)) {
-        infof(data, "Request has same path as previous transfer\n");
+        infof(data, "Request has same path as previous transfer");
         ftpc->cwddone = TRUE;
       }
     }
@@ -4280,11 +4291,11 @@ static CURLcode ftp_doing(struct Curl_easy *data,
   CURLcode result = ftp_multi_statemach(data, dophase_done);
 
   if(result)
-    DEBUGF(infof(data, "DO phase failed\n"));
+    DEBUGF(infof(data, "DO phase failed"));
   else if(*dophase_done) {
     result = ftp_dophase_done(data, FALSE /* not connected */);
 
-    DEBUGF(infof(data, "DO phase is complete2\n"));
+    DEBUGF(infof(data, "DO phase is complete2"));
   }
   return result;
 }
index b25de1d..f7d99ce 100644 (file)
@@ -50,7 +50,6 @@
 #include "hostip.h"
 #include "hash.h"
 #include "share.h"
-#include "strerror.h"
 #include "url.h"
 #include "curl_memory.h"
 /* The last #include file should be: */
index 49dbab3..cf267a7 100644 (file)
@@ -36,7 +36,7 @@
 
 #include "hostcheck.h"
 #include "strcase.h"
-#include "inet_pton.h"
+#include "hostip.h"
 
 #include "curl_memory.h"
 /* The last #include file should be: */
@@ -67,10 +67,6 @@ static int hostmatch(char *hostname, char *pattern)
   const char *pattern_label_end, *pattern_wildcard, *hostname_label_end;
   int wildcard_enabled;
   size_t prefixlen, suffixlen;
-  struct in_addr ignored;
-#ifdef ENABLE_IPV6
-  struct sockaddr_in6 si6;
-#endif
 
   /* normalize pattern and hostname by stripping off trailing dots */
   size_t len = strlen(hostname);
@@ -86,12 +82,8 @@ static int hostmatch(char *hostname, char *pattern)
       CURL_HOST_MATCH : CURL_HOST_NOMATCH;
 
   /* detect IP address as hostname and fail the match if so */
-  if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0)
-    return CURL_HOST_NOMATCH;
-#ifdef ENABLE_IPV6
-  if(Curl_inet_pton(AF_INET6, hostname, &si6.sin6_addr) > 0)
+  if(Curl_host_is_ipnum(hostname))
     return CURL_HOST_NOMATCH;
-#endif
 
   /* We require at least 2 dots in pattern to avoid too wide wildcard
      match. */
index e0e3cfc..117caa2 100644 (file)
 #include "hash.h"
 #include "rand.h"
 #include "share.h"
-#include "strerror.h"
 #include "url.h"
 #include "inet_ntop.h"
 #include "inet_pton.h"
 #include "multiif.h"
 #include "doh.h"
 #include "warnless.h"
+#include "strcase.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -289,7 +289,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
     user.cache_timeout = data->set.dns_cache_timeout;
 
     if(hostcache_timestamp_remove(&user, dns)) {
-      infof(data, "Hostname in DNS cache was stale, zapped\n");
+      infof(data, "Hostname in DNS cache was stale, zapped");
       dns = NULL; /* the memory deallocation is being handled by the hash */
       Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
     }
@@ -460,6 +460,127 @@ Curl_cache_addr(struct Curl_easy *data,
   return dns;
 }
 
+#ifdef ENABLE_IPV6
+/* return a static IPv6 resolve for 'localhost' */
+static struct Curl_addrinfo *get_localhost6(int port)
+{
+  struct Curl_addrinfo *ca;
+  const size_t ss_size = sizeof(struct sockaddr_in6);
+  const size_t hostlen = strlen("localhost");
+  struct sockaddr_in6 sa6;
+  unsigned char ipv6[16];
+  unsigned short port16 = (unsigned short)(port & 0xffff);
+  ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1);
+  if(!ca)
+    return NULL;
+
+  sa6.sin6_family = AF_INET6;
+  sa6.sin6_port = htons(port16);
+  sa6.sin6_flowinfo = 0;
+  sa6.sin6_scope_id = 0;
+  if(Curl_inet_pton(AF_INET6, "::1", ipv6) < 1)
+    return NULL;
+  memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6));
+
+  ca->ai_flags     = 0;
+  ca->ai_family    = AF_INET6;
+  ca->ai_socktype  = SOCK_STREAM;
+  ca->ai_protocol  = IPPROTO_TCP;
+  ca->ai_addrlen   = (curl_socklen_t)ss_size;
+  ca->ai_next      = NULL;
+  ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
+  memcpy(ca->ai_addr, &sa6, ss_size);
+  ca->ai_canonname = (char *)ca->ai_addr + ss_size;
+  strcpy(ca->ai_canonname, "localhost");
+  return ca;
+}
+#else
+#define get_localhost6(x) NULL
+#endif
+
+/* return a static IPv4 resolve for 'localhost' */
+static struct Curl_addrinfo *get_localhost(int port)
+{
+  struct Curl_addrinfo *ca;
+  const size_t ss_size = sizeof(struct sockaddr_in);
+  const size_t hostlen = strlen("localhost");
+  struct sockaddr_in sa;
+  unsigned int ipv4;
+  unsigned short port16 = (unsigned short)(port & 0xffff);
+  ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1);
+  if(!ca)
+    return NULL;
+
+  /* memset to clear the sa.sin_zero field */
+  memset(&sa, 0, sizeof(sa));
+  sa.sin_family = AF_INET;
+  sa.sin_port = htons(port16);
+  if(Curl_inet_pton(AF_INET, "127.0.0.1", (char *)&ipv4) < 1)
+    return NULL;
+  memcpy(&sa.sin_addr, &ipv4, sizeof(ipv4));
+
+  ca->ai_flags     = 0;
+  ca->ai_family    = AF_INET;
+  ca->ai_socktype  = SOCK_STREAM;
+  ca->ai_protocol  = IPPROTO_TCP;
+  ca->ai_addrlen   = (curl_socklen_t)ss_size;
+  ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
+  memcpy(ca->ai_addr, &sa, ss_size);
+  ca->ai_canonname = (char *)ca->ai_addr + ss_size;
+  strcpy(ca->ai_canonname, "localhost");
+  ca->ai_next = get_localhost6(port);
+  return ca;
+}
+
+#ifdef ENABLE_IPV6
+/*
+ * Curl_ipv6works() returns TRUE if IPv6 seems to work.
+ */
+bool Curl_ipv6works(struct Curl_easy *data)
+{
+  if(data) {
+    /* the nature of most system is that IPv6 status doesn't come and go
+       during a program's lifetime so we only probe the first time and then we
+       have the info kept for fast re-use */
+    DEBUGASSERT(data);
+    DEBUGASSERT(data->multi);
+    return data->multi->ipv6_works;
+  }
+  else {
+    int ipv6_works = -1;
+    /* probe to see if we have a working IPv6 stack */
+    curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
+    if(s == CURL_SOCKET_BAD)
+      /* an IPv6 address was requested but we can't get/use one */
+      ipv6_works = 0;
+    else {
+      ipv6_works = 1;
+      sclose(s);
+    }
+    return (ipv6_works>0)?TRUE:FALSE;
+  }
+}
+#endif /* ENABLE_IPV6 */
+
+/*
+ * Curl_host_is_ipnum() returns TRUE if the given string is a numerical IPv4
+ * (or IPv6 if supported) address.
+ */
+bool Curl_host_is_ipnum(const char *hostname)
+{
+  struct in_addr in;
+#ifdef ENABLE_IPV6
+  struct in6_addr in6;
+#endif
+  if(Curl_inet_pton(AF_INET, hostname, &in) > 0
+#ifdef ENABLE_IPV6
+     || Curl_inet_pton(AF_INET6, hostname, &in6) > 0
+#endif
+    )
+    return TRUE;
+  return FALSE;
+}
+
 /*
  * Curl_resolv() is the main name resolve function within libcurl. It resolves
  * a name and returns a pointer to the entry in the 'entry' argument (if one
@@ -487,7 +608,6 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
   CURLcode result;
   enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */
   struct connectdata *conn = data->conn;
-
   *entry = NULL;
   conn->bits.doh = FALSE; /* default is not */
 
@@ -497,7 +617,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
   dns = fetch_addr(data, hostname, port);
 
   if(dns) {
-    infof(data, "Hostname %s was found in DNS cache\n", hostname);
+    infof(data, "Hostname %s was found in DNS cache", hostname);
     dns->inuse++; /* we use it! */
     rc = CURLRESOLV_RESOLVED;
   }
@@ -534,16 +654,20 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
     }
 
 #if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES)
-    /*
-     * The automagic conversion from IPv4 literals to IPv6 literals only works
-     * if the SCDynamicStoreCopyProxies system function gets called first. As
-     * Curl currently doesn't support system-wide HTTP proxies, we therefore
-     * don't use any value this function might return.
-     *
-     * This function is only available on a macOS and is not needed for
-     * IPv4-only builds, hence the conditions above.
-     */
-    SCDynamicStoreCopyProxies(NULL);
+    {
+      /*
+       * The automagic conversion from IPv4 literals to IPv6 literals only
+       * works if the SCDynamicStoreCopyProxies system function gets called
+       * first. As Curl currently doesn't support system-wide HTTP proxies, we
+       * therefore don't use any value this function might return.
+       *
+       * This function is only available on a macOS and is not needed for
+       * IPv4-only builds, hence the conditions above.
+       */
+      CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
+      if(dict)
+        CFRelease(dict);
+    }
 #endif
 
 #ifndef USE_RESOLVE_ON_IPS
@@ -579,15 +703,18 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
 #endif /* !USE_RESOLVE_ON_IPS */
 
     if(!addr) {
-      /* Check what IP specifics the app has requested and if we can provide
-       * it. If not, bail out. */
-      if(!Curl_ipvalid(data, conn))
+      if(conn->ip_version == CURL_IPRESOLVE_V6 && !Curl_ipv6works(data))
         return CURLRESOLV_ERROR;
 
-      if(allowDOH && data->set.doh && !ipnum) {
+      if(strcasecompare(hostname, "localhost"))
+        addr = get_localhost(port);
+      else if(allowDOH && data->set.doh && !ipnum)
         addr = Curl_doh(data, hostname, port, &respwait);
-      }
       else {
+        /* Check what IP specifics the app has requested and if we can provide
+         * it. If not, bail out. */
+        if(!Curl_ipvalid(data, conn))
+          return CURLRESOLV_ERROR;
         /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
            non-zero value indicating that we need to wait for the response to
            the resolve call */
@@ -757,7 +884,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
 #else
 #ifndef CURLRES_ASYNCH
   if(timeoutms)
-    infof(data, "timeout on name lookup is not supported\n");
+    infof(data, "timeout on name lookup is not supported");
 #else
   (void)timeoutms; /* timeoutms not used with an async resolver */
 #endif
@@ -895,7 +1022,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       size_t entry_len;
 
       if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) {
-        infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n",
+        infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'",
               hostp->data);
         continue;
       }
@@ -984,7 +1111,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
 
 #ifndef ENABLE_IPV6
         if(strchr(address, ':')) {
-          infof(data, "Ignoring resolve address '%s', missing IPv6 support.\n",
+          infof(data, "Ignoring resolve address '%s', missing IPv6 support.",
                 address);
           continue;
         }
@@ -992,7 +1119,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
 
         ai = Curl_str2addr(address, port);
         if(!ai) {
-          infof(data, "Resolve address '%s' found illegal!\n", address);
+          infof(data, "Resolve address '%s' found illegal!", address);
           goto err;
         }
 
@@ -1011,10 +1138,10 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       error = false;
    err:
       if(error) {
-        infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n",
+        failf(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!",
               hostp->data);
         Curl_freeaddrinfo(head);
-        continue;
+        return CURLE_SETOPT_OPTION_SYNTAX;
       }
 
       /* Create an entry id, based upon the hostname and port */
@@ -1028,7 +1155,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
 
       if(dns) {
-        infof(data, "RESOLVE %s:%d is - old addresses discarded!\n",
+        infof(data, "RESOLVE %s:%d is - old addresses discarded!",
                 hostname, port);
         /* delete old entry, there are two reasons for this
          1. old entry may have different addresses.
@@ -1061,12 +1188,12 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
         Curl_freeaddrinfo(head);
         return CURLE_OUT_OF_MEMORY;
       }
-      infof(data, "Added %s:%d:%s to DNS cache%s\n",
+      infof(data, "Added %s:%d:%s to DNS cache%s",
             hostname, port, addresses, permanent ? "" : " (non-permanent)");
 
       /* Wildcard hostname */
       if(hostname[0] == '*' && hostname[1] == '\0') {
-        infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks\n",
+        infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks",
               hostname, port);
         data->state.wildcard_resolve = true;
       }
@@ -1094,7 +1221,7 @@ int Curl_resolv_getsock(struct Curl_easy *data,
 {
 #ifdef CURLRES_ASYNCH
   if(data->conn->bits.doh)
-    /* nothing to wait for during DOH resolve, those handles have their own
+    /* nothing to wait for during DoH resolve, those handles have their own
        sockets */
     return GETSOCK_BLANK;
   return Curl_resolver_getsock(data, socks);
index d178976..67a688a 100644 (file)
@@ -71,6 +71,8 @@ struct Curl_dns_entry {
   long inuse;
 };
 
+bool Curl_host_is_ipnum(const char *hostname);
+
 /*
  * Curl_resolv() returns an entry with the info for the specified host
  * and port.
@@ -95,7 +97,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
                                    struct Curl_dns_entry **dnsentry,
                                    timediff_t timeoutms);
 
-#ifdef CURLRES_IPV6
+#ifdef ENABLE_IPV6
 /*
  * Curl_ipv6works() returns TRUE if IPv6 seems to work.
  */
index d0754af..1fd7910 100644 (file)
@@ -50,7 +50,6 @@
 #include "hostip.h"
 #include "hash.h"
 #include "share.h"
-#include "strerror.h"
 #include "url.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -104,7 +103,7 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
 
   ai = Curl_ipv4_resolve_r(hostname, port);
   if(!ai)
-    infof(data, "Curl_ipv4_resolve_r failed for %s\n", hostname);
+    infof(data, "Curl_ipv4_resolve_r failed for %s", hostname);
 
   return ai;
 }
index 9791d86..c2d5f08 100644 (file)
@@ -50,7 +50,6 @@
 #include "hostip.h"
 #include "hash.h"
 #include "share.h"
-#include "strerror.h"
 #include "url.h"
 #include "inet_pton.h"
 #include "connect.h"
 #include "memdebug.h"
 
 /*
- * Curl_ipv6works() returns TRUE if IPv6 seems to work.
- */
-bool Curl_ipv6works(struct Curl_easy *data)
-{
-  if(data) {
-    /* the nature of most system is that IPv6 status doesn't come and go
-       during a program's lifetime so we only probe the first time and then we
-       have the info kept for fast re-use */
-    DEBUGASSERT(data);
-    DEBUGASSERT(data->multi);
-    return data->multi->ipv6_works;
-  }
-  else {
-    int ipv6_works = -1;
-    /* probe to see if we have a working IPv6 stack */
-    curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
-    if(s == CURL_SOCKET_BAD)
-      /* an IPv6 address was requested but we can't get/use one */
-      ipv6_works = 0;
-    else {
-      ipv6_works = 1;
-      sclose(s);
-    }
-    return (ipv6_works>0)?TRUE:FALSE;
-  }
-}
-
-/*
  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
  * been set and returns TRUE if they are OK.
  */
@@ -172,7 +143,7 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
 
   error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);
   if(error) {
-    infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
+    infof(data, "getaddrinfo(3) failed for %s:%d", hostname, port);
     return NULL;
   }
 
index 550b43a..c00c274 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -50,7 +50,6 @@
 #include "hostip.h"
 #include "hash.h"
 #include "share.h"
-#include "strerror.h"
 #include "url.h"
 #include "curl_memory.h"
 /* The last #include file should be: */
index ef166f1..052dc11 100644 (file)
@@ -49,6 +49,7 @@
 #define MAX_HSTS_HOSTLENSTR "256"
 #define MAX_HSTS_DATELEN 64
 #define MAX_HSTS_DATELENSTR "64"
+#define UNLIMITED "unlimited"
 
 #ifdef DEBUGBUILD
 /* to play well with debug builds, we can *set* a fixed time this will
@@ -138,6 +139,11 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
   struct stsentry *sts;
   time_t now = time(NULL);
 
+  if(Curl_host_is_ipnum(hostname))
+    /* "explicit IP address identification of all forms is excluded."
+       / RFC 6797 */
+    return CURLE_OK;
+
   do {
     while(*p && ISSPACE(*p))
       p++;
@@ -278,13 +284,17 @@ static CURLcode hsts_push(struct Curl_easy *data,
   e.namelen = strlen(sts->host);
   e.includeSubDomains = sts->includeSubDomains;
 
-  result = Curl_gmtime((time_t)sts->expires, &stamp);
-  if(result)
-    return result;
+  if(sts->expires != TIME_T_MAX) {
+    result = Curl_gmtime((time_t)sts->expires, &stamp);
+    if(result)
+      return result;
 
-  msnprintf(e.expire, sizeof(e.expire), "%d%02d%02d %02d:%02d:%02d",
-            stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
-            stamp.tm_hour, stamp.tm_min, stamp.tm_sec);
+    msnprintf(e.expire, sizeof(e.expire), "%d%02d%02d %02d:%02d:%02d",
+              stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
+              stamp.tm_hour, stamp.tm_min, stamp.tm_sec);
+  }
+  else
+    strcpy(e.expire, UNLIMITED);
 
   sc = data->set.hsts_write(data, &e, i,
                             data->set.hsts_write_userp);
@@ -298,14 +308,18 @@ static CURLcode hsts_push(struct Curl_easy *data,
 static CURLcode hsts_out(struct stsentry *sts, FILE *fp)
 {
   struct tm stamp;
-  CURLcode result = Curl_gmtime((time_t)sts->expires, &stamp);
-  if(result)
-    return result;
-
-  fprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n",
-          sts->includeSubDomains ? ".": "", sts->host,
-          stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
-          stamp.tm_hour, stamp.tm_min, stamp.tm_sec);
+  if(sts->expires != TIME_T_MAX) {
+    CURLcode result = Curl_gmtime((time_t)sts->expires, &stamp);
+    if(result)
+      return result;
+    fprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n",
+            sts->includeSubDomains ? ".": "", sts->host,
+            stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
+            stamp.tm_hour, stamp.tm_min, stamp.tm_sec);
+  }
+  else
+    fprintf(fp, "%s%s \"%s\"\n",
+            sts->includeSubDomains ? ".": "", sts->host, UNLIMITED);
   return CURLE_OK;
 }
 
@@ -398,7 +412,8 @@ static CURLcode hsts_add(struct hsts *h, char *line)
               "%" MAX_HSTS_HOSTLENSTR "s \"%" MAX_HSTS_DATELENSTR "[^\"]\"",
               host, date);
   if(2 == rc) {
-    time_t expires = Curl_getdate_capped(date);
+    time_t expires = strcmp(date, UNLIMITED) ? Curl_getdate_capped(date) :
+      TIME_T_MAX;
     CURLcode result;
     char *p = host;
     bool subdomain = FALSE;
@@ -451,7 +466,7 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
           return result;
       }
       else if(sc == CURLSTS_FAIL)
-        return CURLE_BAD_FUNCTION_ARGUMENT;
+        return CURLE_ABORTED_BY_CALLBACK;
     } while(sc == CURLSTS_OK);
   }
   return CURLE_OK;
@@ -521,7 +536,9 @@ CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
  */
 CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h)
 {
-  return hsts_pull(data, h);
+  if(h)
+    return hsts_pull(data, h);
+  return CURLE_OK;
 }
 
 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
index baa5828..653c053 100644 (file)
@@ -59,7 +59,7 @@ CURLcode Curl_hsts_loadcb(struct Curl_easy *data,
                           struct hsts *h);
 #else
 #define Curl_hsts_cleanup(x)
-#define Curl_hsts_loadcb(x,y)
+#define Curl_hsts_loadcb(x,y) CURLE_OK
 #define Curl_hsts_save(x,y,z)
 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
 #endif /* HEADER_CURL_HSTS_H */
index 628dd73..648583c 100644 (file)
@@ -504,7 +504,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
         /* rewind data when completely done sending! */
         if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) {
           conn->bits.rewindaftersend = TRUE;
-          infof(data, "Rewind stream after send\n");
+          infof(data, "Rewind stream after send");
         }
 
         return CURLE_OK;
@@ -515,7 +515,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
         return CURLE_OK;
 
       infof(data, "NTLM send, close instead of sending %"
-            CURL_FORMAT_CURL_OFF_T " bytes\n",
+            CURL_FORMAT_CURL_OFF_T " bytes",
             (curl_off_t)(expectsend - bytessent));
     }
 #endif
@@ -532,7 +532,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
         /* rewind data when completely done sending! */
         if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) {
           conn->bits.rewindaftersend = TRUE;
-          infof(data, "Rewind stream after send\n");
+          infof(data, "Rewind stream after send");
         }
 
         return CURLE_OK;
@@ -543,7 +543,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
         return CURLE_OK;
 
       infof(data, "NEGOTIATE send, close instead of sending %"
-        CURL_FORMAT_CURL_OFF_T " bytes\n",
+        CURL_FORMAT_CURL_OFF_T " bytes",
         (curl_off_t)(expectsend - bytessent));
     }
 #endif
@@ -756,14 +756,14 @@ output_auth_headers(struct Curl_easy *data,
 
   if(auth) {
 #ifndef CURL_DISABLE_PROXY
-    infof(data, "%s auth using %s with user '%s'\n",
+    infof(data, "%s auth using %s with user '%s'",
           proxy ? "Proxy" : "Server", auth,
           proxy ? (data->state.aptr.proxyuser ?
                    data->state.aptr.proxyuser : "") :
           (data->state.aptr.user ?
            data->state.aptr.user : ""));
 #else
-    infof(data, "Server auth using %s with user '%s'\n",
+    infof(data, "Server auth using %s with user '%s'",
           auth, data->state.aptr.user ?
           data->state.aptr.user : "");
 #endif
@@ -850,7 +850,9 @@ Curl_http_output_auth(struct Curl_easy *data,
   /* To prevent the user+password to get sent to other than the original
      host due to a location-follow, we do some weirdo checks here */
   if(!data->state.this_is_a_follow ||
+#ifndef CURL_DISABLE_NETRC
      conn->bits.netrc ||
+#endif
      !data->state.first_host ||
      data->set.allow_auth_to_other_hosts ||
      strcasecompare(data->state.first_host, conn->host.name)) {
@@ -995,14 +997,14 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
 
                 result = Curl_input_ntlm_wb(data, conn, proxy, auth);
                 if(result) {
-                  infof(data, "Authentication problem. Ignoring this.\n");
+                  infof(data, "Authentication problem. Ignoring this.");
                   data->state.authproblem = TRUE;
                 }
               }
 #endif
             }
             else {
-              infof(data, "Authentication problem. Ignoring this.\n");
+              infof(data, "Authentication problem. Ignoring this.");
               data->state.authproblem = TRUE;
             }
           }
@@ -1013,7 +1015,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
 #ifndef CURL_DISABLE_CRYPTO_AUTH
         if(checkprefix("Digest", auth) && is_valid_auth_separator(auth[6])) {
           if((authp->avail & CURLAUTH_DIGEST) != 0)
-            infof(data, "Ignoring duplicate digest auth header.\n");
+            infof(data, "Ignoring duplicate digest auth header.");
           else if(Curl_auth_is_digest_supported()) {
             CURLcode result;
 
@@ -1026,7 +1028,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
              * Digest */
             result = Curl_input_digest(data, proxy, auth);
             if(result) {
-              infof(data, "Authentication problem. Ignoring this.\n");
+              infof(data, "Authentication problem. Ignoring this.");
               data->state.authproblem = TRUE;
             }
           }
@@ -1042,7 +1044,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
                  anyway, which basically means our name+password isn't
                  valid. */
               authp->avail = CURLAUTH_NONE;
-              infof(data, "Authentication problem. Ignoring this.\n");
+              infof(data, "Authentication problem. Ignoring this.");
               data->state.authproblem = TRUE;
             }
           }
@@ -1055,7 +1057,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
                 /* We asked for Bearer authentication but got a 40X back
                   anyway, which basically means our token isn't valid. */
                 authp->avail = CURLAUTH_NONE;
-                infof(data, "Authentication problem. Ignoring this.\n");
+                infof(data, "Authentication problem. Ignoring this.");
                 data->state.authproblem = TRUE;
               }
             }
@@ -1177,6 +1179,7 @@ static size_t readmoredata(char *buffer,
   data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
 
   if(data->set.max_send_speed &&
+     (data->set.max_send_speed < (curl_off_t)fullsize) &&
      (data->set.max_send_speed < http->postsize))
     /* speed limit */
     fullsize = (size_t)data->set.max_send_speed;
@@ -1537,38 +1540,35 @@ static int http_getsock_do(struct Curl_easy *data,
 #ifndef CURL_DISABLE_PROXY
 static CURLcode add_haproxy_protocol_header(struct Curl_easy *data)
 {
-  char proxy_header[128];
   struct dynbuf req;
   CURLcode result;
-  char tcp_version[5];
+  const char *tcp_version;
   DEBUGASSERT(data->conn);
+  Curl_dyn_init(&req, DYN_HAXPROXY);
 
-  /* Emit the correct prefix for IPv6 */
-  if(data->conn->bits.ipv6) {
-    strcpy(tcp_version, "TCP6");
-  }
+#ifdef USE_UNIX_SOCKETS
+  if(data->conn->unix_domain_socket)
+    /* the buffer is large enough to hold this! */
+    result = Curl_dyn_add(&req, "PROXY UNKNOWN\r\n");
   else {
-    strcpy(tcp_version, "TCP4");
-  }
-
-  msnprintf(proxy_header,
-            sizeof(proxy_header),
-            "PROXY %s %s %s %i %i\r\n",
-            tcp_version,
-            data->info.conn_local_ip,
-            data->info.conn_primary_ip,
-            data->info.conn_local_port,
-            data->info.conn_primary_port);
-
-  Curl_dyn_init(&req, DYN_HAXPROXY);
+#endif
+  /* Emit the correct prefix for IPv6 */
+  tcp_version = data->conn->bits.ipv6 ? "TCP6" : "TCP4";
 
-  result = Curl_dyn_add(&req, proxy_header);
-  if(result)
-    return result;
+  result = Curl_dyn_addf(&req, "PROXY %s %s %s %i %i\r\n",
+                         tcp_version,
+                         data->info.conn_local_ip,
+                         data->info.conn_primary_ip,
+                         data->info.conn_local_port,
+                         data->info.conn_primary_port);
 
-  result = Curl_buffer_send(&req, data, &data->info.request_size,
-                            0, FIRSTSOCKET);
+#ifdef USE_UNIX_SOCKETS
+  }
+#endif
 
+  if(!result)
+    result = Curl_buffer_send(&req, data, &data->info.request_size,
+                              0, FIRSTSOCKET);
   return result;
 }
 #endif
@@ -1588,7 +1588,7 @@ static CURLcode https_connecting(struct Curl_easy *data, bool *done)
 #endif
 
   /* perform SSL initialization for this socket */
-  result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET, done);
+  result = Curl_ssl_connect_nonblocking(data, conn, FALSE, FIRSTSOCKET, done);
   if(result)
     connclose(conn, "Failed HTTPS connection");
 
@@ -1669,8 +1669,8 @@ CURLcode Curl_http_done(struct Curl_easy *data,
  * - if any server previously contacted to handle this request only supports
  * 1.0.
  */
-static bool use_http_1_1plus(const struct Curl_easy *data,
-                             const struct connectdata *conn)
+bool Curl_use_http_1_1plus(const struct Curl_easy *data,
+                           const struct connectdata *conn)
 {
   if((data->state.httpversion == 10) || (conn->httpversion == 10))
     return FALSE;
@@ -1696,7 +1696,7 @@ static const char *get_http_string(const struct Curl_easy *data,
     return "2";
 #endif
 
-  if(use_http_1_1plus(data, conn))
+  if(Curl_use_http_1_1plus(data, conn))
     return "1.1";
 
   return "1.0";
@@ -1711,7 +1711,7 @@ static CURLcode expect100(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   data->state.expect100header = FALSE; /* default to false unless it is set
                                           to TRUE below */
-  if(!data->state.disableexpect && use_http_1_1plus(data, conn) &&
+  if(!data->state.disableexpect && Curl_use_http_1_1plus(data, conn) &&
      (conn->httpversion < 20)) {
     /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
        Expect: 100-continue to the headers which actually speeds up post
@@ -2348,7 +2348,7 @@ CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
       if(conn->bits.authneg)
         /* don't enable chunked during auth neg */
         ;
-      else if(use_http_1_1plus(data, conn)) {
+      else if(Curl_use_http_1_1plus(data, conn)) {
         if(conn->httpversion < 20)
           /* HTTP, upload, unknown file size and not HTTP 1.0 */
           data->req.upload_chunky = TRUE;
@@ -2711,14 +2711,16 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
     int count = 0;
 
     if(data->cookies && data->state.cookie_engine) {
+      const char *host = data->state.aptr.cookiehost ?
+        data->state.aptr.cookiehost : conn->host.name;
+      const bool secure_context =
+        conn->handler->protocol&CURLPROTO_HTTPS ||
+        strcasecompare("localhost", host) ||
+        !strcmp(host, "127.0.0.1") ||
+        !strcmp(host, "[::1]") ? TRUE : FALSE;
       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
-      co = Curl_cookie_getlist(data->cookies,
-                               data->state.aptr.cookiehost?
-                               data->state.aptr.cookiehost:
-                               conn->host.name,
-                               data->state.up.path,
-                               (conn->handler->protocol&CURLPROTO_HTTPS)?
-                               TRUE:FALSE);
+      co = Curl_cookie_getlist(data->cookies, host, data->state.up.path,
+                               secure_context);
       Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
     }
     if(co) {
@@ -2901,6 +2903,20 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
 {
   struct SingleRequest *k = &data->req;
   DEBUGASSERT(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP));
+  if(data->req.ignore_cl) {
+    k->size = k->maxdownload = -1;
+  }
+  else if(k->size != -1) {
+    /* We wait until after all headers have been received to set this so that
+       we know for sure Content-Length is valid. */
+    if(data->set.max_filesize &&
+       k->size > data->set.max_filesize) {
+      failf(data, "Maximum file size exceeded");
+      return CURLE_FILESIZE_EXCEEDED;
+    }
+    Curl_pgrsSetDownloadSize(data, k->size);
+  }
+
   if(data->req.newurl) {
     if(conn->bits.close) {
       /* Abort after the headers if "follow Location" is set
@@ -2912,7 +2928,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
     /* We have a new url to load, but since we want to be able to re-use this
        connection properly, we read the full response in "ignore more" */
     k->ignorebody = TRUE;
-    infof(data, "Ignoring the response-body\n");
+    infof(data, "Ignoring the response-body");
   }
   if(data->state.resume_from && !k->content_range &&
      (data->state.httpreq == HTTPREQ_GET) &&
@@ -2947,7 +2963,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
       /* We're simulating a http 304 from server so we return
          what should have been returned from the server */
       data->info.httpcode = 304;
-      infof(data, "Simulate a HTTP 304 response!\n");
+      infof(data, "Simulate a HTTP 304 response!");
       /* we abort the transfer before it is completed == we ruin the
          re-use ability. Close the connection */
       connclose(conn, "Simulated 304 handling");
@@ -2958,6 +2974,39 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
   return CURLE_OK;
 }
 
+#ifdef HAVE_LIBZ
+CURLcode Curl_transferencode(struct Curl_easy *data)
+{
+  if(!Curl_checkheaders(data, "TE") &&
+     data->set.http_transfer_encoding) {
+    /* When we are to insert a TE: header in the request, we must also insert
+       TE in a Connection: header, so we need to merge the custom provided
+       Connection: header and prevent the original to get sent. Note that if
+       the user has inserted his/her own TE: header we don't do this magic
+       but then assume that the user will handle it all! */
+    char *cptr = Curl_checkheaders(data, "Connection");
+#define TE_HEADER "TE: gzip\r\n"
+
+    Curl_safefree(data->state.aptr.te);
+
+    if(cptr) {
+      cptr = Curl_copy_header_value(cptr);
+      if(!cptr)
+        return CURLE_OUT_OF_MEMORY;
+    }
+
+    /* Create the (updated) Connection: header */
+    data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
+                                cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
+
+    free(cptr);
+    if(!data->state.aptr.te)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  return CURLE_OK;
+}
+#endif
+
 #ifndef USE_HYPER
 /*
  * Curl_http() gets called from the generic multi_do() function when a HTTP
@@ -3004,11 +3053,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
           if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
             /* We don't support HTTP/2 proxies yet. Also it's debatable
                whether or not this setting should apply to HTTP/2 proxies. */
-            infof(data, "Ignoring HTTP/2 prior knowledge due to proxy\n");
+            infof(data, "Ignoring HTTP/2 prior knowledge due to proxy");
             break;
           }
 #endif
-          DEBUGF(infof(data, "HTTP/2 over clean TCP\n"));
+          DEBUGF(infof(data, "HTTP/2 over clean TCP"));
           conn->httpversion = 20;
 
           result = Curl_http2_switched(data, NULL, 0);
@@ -3074,33 +3123,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
 
 #ifdef HAVE_LIBZ
   /* we only consider transfer-encoding magic if libz support is built-in */
-
-  if(!Curl_checkheaders(data, "TE") &&
-     data->set.http_transfer_encoding) {
-    /* When we are to insert a TE: header in the request, we must also insert
-       TE in a Connection: header, so we need to merge the custom provided
-       Connection: header and prevent the original to get sent. Note that if
-       the user has inserted his/her own TE: header we don't do this magic
-       but then assume that the user will handle it all! */
-    char *cptr = Curl_checkheaders(data, "Connection");
-#define TE_HEADER "TE: gzip\r\n"
-
-    Curl_safefree(data->state.aptr.te);
-
-    if(cptr) {
-      cptr = Curl_copy_header_value(cptr);
-      if(!cptr)
-        return CURLE_OUT_OF_MEMORY;
-    }
-
-    /* Create the (updated) Connection: header */
-    data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
-                                cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
-
-    free(cptr);
-    if(!data->state.aptr.te)
-      return CURLE_OUT_OF_MEMORY;
-  }
+  result = Curl_transferencode(data);
+  if(result)
+    return result;
 #endif
 
   result = Curl_http_body(data, conn, httpreq, &te);
@@ -3253,7 +3278,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
       /* already sent the entire request body, mark the "upload" as
          complete */
       infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
-            " out of %" CURL_FORMAT_CURL_OFF_T " bytes\n",
+            " out of %" CURL_FORMAT_CURL_OFF_T " bytes",
             data->req.writebytecount, http->postsize);
       data->req.upload_done = TRUE;
       data->req.keepon &= ~KEEP_SEND; /* we're done writing */
@@ -3392,17 +3417,8 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
                                     NULL, 10, &contentlength);
 
     if(offt == CURL_OFFT_OK) {
-      if(data->set.max_filesize &&
-         contentlength > data->set.max_filesize) {
-        failf(data, "Maximum file size exceeded");
-        return CURLE_FILESIZE_EXCEEDED;
-      }
       k->size = contentlength;
       k->maxdownload = k->size;
-      /* we set the progress download size already at this point
-         just to make it easier for apps/callbacks to extract this
-         info as soon as possible */
-      Curl_pgrsSetDownloadSize(data, k->size);
     }
     else if(offt == CURL_OFFT_FLOW) {
       /* out of range */
@@ -3411,7 +3427,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
         return CURLE_FILESIZE_EXCEEDED;
       }
       streamclose(conn, "overflow content-length");
-      infof(data, "Overflow Content-Length: value!\n");
+      infof(data, "Overflow Content-Length: value!");
     }
     else {
       /* negative or just rubbish - bad HTTP */
@@ -3443,7 +3459,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
      * Default action for 1.0 is to close.
      */
     connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
-    infof(data, "HTTP/1.0 proxy connection set to keep alive!\n");
+    infof(data, "HTTP/1.0 proxy connection set to keep alive!");
   }
   else if((conn->httpversion == 11) &&
           conn->bits.httpproxy &&
@@ -3453,7 +3469,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
      * close down after this transfer.
      */
     connclose(conn, "Proxy-Connection: asked to close after done");
-    infof(data, "HTTP/1.1 proxy connection set close!\n");
+    infof(data, "HTTP/1.1 proxy connection set close!");
   }
 #endif
   else if((conn->httpversion == 10) &&
@@ -3465,7 +3481,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
      *
      * [RFC2068, section 19.7.1] */
     connkeep(conn, "Connection keep-alive");
-    infof(data, "HTTP/1.0 connection set to keep alive!\n");
+    infof(data, "HTTP/1.0 connection set to keep alive!");
   }
   else if(Curl_compareheader(headp, "Connection:", "close")) {
     /*
@@ -3493,6 +3509,12 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
                                          TRUE);
     if(result)
       return result;
+    if(!k->chunk) {
+      /* if this isn't chunked, only close can signal the end of this transfer
+         as Content-Length is said not to be trusted for transfer-encoding! */
+      connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
+      k->ignore_cl = TRUE;
+    }
   }
   else if(!k->http_bodyless && checkprefix("Content-Encoding:", headp) &&
           data->set.str[STRING_ENCODING]) {
@@ -3555,18 +3577,21 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
 #if !defined(CURL_DISABLE_COOKIES)
   else if(data->cookies && data->state.cookie_engine &&
           checkprefix("Set-Cookie:", headp)) {
+    /* If there is a custom-set Host: name, use it here, or else use real peer
+       host name. */
+    const char *host = data->state.aptr.cookiehost?
+      data->state.aptr.cookiehost:conn->host.name;
+    const bool secure_context =
+      conn->handler->protocol&CURLPROTO_HTTPS ||
+      strcasecompare("localhost", host) ||
+      !strcmp(host, "127.0.0.1") ||
+      !strcmp(host, "[::1]") ? TRUE : FALSE;
+
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
                     CURL_LOCK_ACCESS_SINGLE);
-    Curl_cookie_add(data,
-                    data->cookies, TRUE, FALSE,
-                    headp + strlen("Set-Cookie:"),
-                    /* If there is a custom-set Host: name, use it
-                       here, or else use real peer host name. */
-                    data->state.aptr.cookiehost?
-                    data->state.aptr.cookiehost:conn->host.name,
-                    data->state.up.path,
-                    (conn->handler->protocol&CURLPROTO_HTTPS)?
-                    TRUE:FALSE);
+    Curl_cookie_add(data, data->cookies, TRUE, FALSE,
+                    headp + strlen("Set-Cookie:"), host,
+                    data->state.up.path, secure_context);
     Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
   }
 #endif
@@ -3646,10 +3671,10 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
       Curl_hsts_parse(data->hsts, data->state.up.hostname,
                       headp + strlen("Strict-Transport-Security:"));
     if(check)
-      infof(data, "Illegal STS header skipped\n");
+      infof(data, "Illegal STS header skipped");
 #ifdef DEBUGBUILD
     else
-      infof(data, "Parsed STS header fine (%zu entries)\n",
+      infof(data, "Parsed STS header fine (%zu entries)",
             data->hsts->list.size);
 #endif
   }
@@ -3719,12 +3744,12 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
     /* Default action for HTTP/1.0 must be to close, unless
        we get one of those fancy headers that tell us the
        server keeps it open for us! */
-    infof(data, "HTTP 1.0, assume close after body\n");
+    infof(data, "HTTP 1.0, assume close after body");
     connclose(conn, "HTTP/1.0 close after body");
   }
   else if(conn->httpversion == 20 ||
           (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) {
-    DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n"));
+    DEBUGF(infof(data, "HTTP/2 found, allow multiplexing"));
     /* HTTP/2 cannot avoid multiplexing since it is a core functionality
        of the protocol */
     conn->bundle->multiuse = BUNDLE_MULTIPLEX;
@@ -3733,7 +3758,7 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
           !conn->bits.close) {
     /* If HTTP version is >= 1.1 and connection is persistent */
     DEBUGF(infof(data,
-                 "HTTP 1.1 or later with persistent connection\n"));
+                 "HTTP 1.1 or later with persistent connection"));
   }
 
   k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
@@ -3911,7 +3936,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
           /* Switching Protocols */
           if(k->upgr101 == UPGR101_REQUESTED) {
             /* Switching to HTTP/2 */
-            infof(data, "Received 101\n");
+            infof(data, "Received 101");
             k->upgr101 = UPGR101_RECEIVED;
 
             /* we'll get more headers (HTTP/2 response) */
@@ -3951,7 +3976,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
              assume that the server will close the connection to
              signal the end of the document. */
           infof(data, "no chunk, no close, no size. Assume close to "
-                "signal end\n");
+                "signal end");
           streamclose(conn, "HTTP: No end-of-message indicator");
         }
       }
@@ -3964,7 +3989,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
            (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
           ((data->req.httpcode == 407) &&
            (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
-        infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n");
+        infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
         data->state.authproblem = TRUE;
       }
 #endif
@@ -3974,7 +3999,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
           (conn->http_negotiate_state == GSS_AUTHRECV)) ||
          ((data->req.httpcode == 407) &&
           (conn->proxy_negotiate_state == GSS_AUTHRECV)))) {
-        infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n");
+        infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
         data->state.authproblem = TRUE;
       }
       if((conn->http_negotiate_state == GSS_AUTHDONE) &&
@@ -4054,21 +4079,21 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
               if((k->httpcode == 417) && data->state.expect100header) {
                 /* 417 Expectation Failed - try again without the Expect
                    header */
-                infof(data, "Got 417 while waiting for a 100\n");
+                infof(data, "Got 417 while waiting for a 100");
                 data->state.disableexpect = TRUE;
                 DEBUGASSERT(!data->req.newurl);
                 data->req.newurl = strdup(data->state.url);
                 Curl_done_sending(data, k);
               }
               else if(data->set.http_keep_sending_on_error) {
-                infof(data, "HTTP error before end of send, keep sending\n");
+                infof(data, "HTTP error before end of send, keep sending");
                 if(k->exp100 > EXP100_SEND_DATA) {
                   k->exp100 = EXP100_SEND_DATA;
                   k->keepon |= KEEP_SEND;
                 }
               }
               else {
-                infof(data, "HTTP error before end of send, stop sending\n");
+                infof(data, "HTTP error before end of send, stop sending");
                 streamclose(conn, "Stop sending data before everything sent");
                 result = Curl_done_sending(data, k);
                 if(result)
@@ -4088,7 +4113,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
         if(conn->bits.rewindaftersend) {
           /* We rewind after a complete send, so thus we continue
              sending now */
-          infof(data, "Keep sending data to get tossed away!\n");
+          infof(data, "Keep sending data to get tossed away!");
           k->keepon |= KEEP_SEND;
         }
       }
@@ -4201,18 +4226,20 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
          * https://tools.ietf.org/html/rfc7230#section-3.1.2
          *
          * The response code is always a three-digit number in HTTP as the spec
-         * says. We try to allow any number here, but we cannot make
+         * says. We allow any three-digit number here, but we cannot make
          * guarantees on future behaviors since it isn't within the protocol.
          */
         char separator;
         char twoorthree[2];
         int httpversion = 0;
+        char digit4 = 0;
         nc = sscanf(HEADER1,
-                    " HTTP/%1d.%1d%c%3d",
+                    " HTTP/%1d.%1d%c%3d%c",
                     &httpversion_major,
                     &httpversion,
                     &separator,
-                    &k->httpcode);
+                    &k->httpcode,
+                    &digit4);
 
         if(nc == 1 && httpversion_major >= 2 &&
            2 == sscanf(HEADER1, " HTTP/%1[23] %d", twoorthree, &k->httpcode)) {
@@ -4221,7 +4248,15 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
           separator = ' ';
         }
 
-        if((nc == 4) && (' ' == separator)) {
+        /* There can only be a 4th response code digit stored in 'digit4' if
+           all the other fields were parsed and stored first, so nc is 5 when
+           digit4 a digit */
+        else if(ISDIGIT(digit4)) {
+          failf(data, "Unsupported response code in HTTP response");
+          return CURLE_UNSUPPORTED_PROTOCOL;
+        }
+
+        if((nc >= 4) && (' ' == separator)) {
           httpversion += 10 * httpversion_major;
           switch(httpversion) {
           case 10:
@@ -4243,11 +4278,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
           if(k->upgr101 == UPGR101_RECEIVED) {
             /* supposedly upgraded to http2 now */
             if(conn->httpversion != 20)
-              infof(data, "Lying server, not serving HTTP/2\n");
+              infof(data, "Lying server, not serving HTTP/2");
           }
           if(conn->httpversion < 20) {
             conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
-            infof(data, "Mark bundle as not supporting multiuse\n");
+            infof(data, "Mark bundle as not supporting multiuse");
           }
         }
         else if(!nc) {
index 2a3834a..e4ab466 100644 (file)
@@ -93,11 +93,14 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
                               struct connectdata *conn);
 CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
                           char *headp);
+CURLcode Curl_transferencode(struct Curl_easy *data);
 CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
                         Curl_HttpReq httpreq,
                         const char **teep);
 CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
                             struct dynbuf *r, Curl_HttpReq httpreq);
+bool Curl_use_http_1_1plus(const struct Curl_easy *data,
+                           const struct connectdata *conn);
 #ifndef CURL_DISABLE_COOKIES
 CURLcode Curl_http_cookies(struct Curl_easy *data,
                            struct connectdata *conn,
index f194c18..6d63f43 100644 (file)
@@ -146,12 +146,12 @@ static CURLcode http2_disconnect(struct Curl_easy *data,
   (void)data;
 #endif
 
-  H2BUGF(infof(data, "HTTP/2 DISCONNECT starts now\n"));
+  H2BUGF(infof(data, "HTTP/2 DISCONNECT starts now"));
 
   nghttp2_session_del(c->h2);
   Curl_safefree(c->inbuf);
 
-  H2BUGF(infof(data, "HTTP/2 DISCONNECT done\n"));
+  H2BUGF(infof(data, "HTTP/2 DISCONNECT done"));
 
   return CURLE_OK;
 }
@@ -196,11 +196,13 @@ static bool http2_connisdead(struct Curl_easy *data, struct connectdata *conn)
           data, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
       if(nread != -1) {
         infof(data,
-              "%d bytes stray data read before trying h2 connection\n",
+              "%d bytes stray data read before trying h2 connection",
               (int)nread);
         httpc->nread_inbuf = 0;
         httpc->inbuflen = nread;
-        (void)h2_process_pending_input(data, httpc, &result);
+        if(h2_process_pending_input(data, httpc, &result) < 0)
+          /* immediate error, considered dead */
+          dead = TRUE;
       }
       else
         /* the read failed so let's say this is dead anyway */
@@ -350,13 +352,12 @@ static const struct Curl_handler Curl_handler_http2_ssl = {
 };
 
 /*
- * Store nghttp2 version info in this buffer, Prefix with a space.  Return
- * total length written.
+ * Store nghttp2 version info in this buffer.
  */
-int Curl_http2_ver(char *p, size_t len)
+void Curl_http2_ver(char *p, size_t len)
 {
   nghttp2_info *h2 = nghttp2_version(0);
-  return msnprintf(p, len, "nghttp2/%s", h2->version_str);
+  (void)msnprintf(p, len, "nghttp2/%s", h2->version_str);
 }
 
 /*
@@ -551,7 +552,7 @@ static int push_promise(struct Curl_easy *data,
                         const nghttp2_push_promise *frame)
 {
   int rv; /* one of the CURL_PUSH_* defines */
-  H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!\n",
+  H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!",
                frame->promised_stream_id));
   if(data->multi->push_cb) {
     struct HTTP *stream;
@@ -563,7 +564,7 @@ static int push_promise(struct Curl_easy *data,
     /* clone the parent */
     struct Curl_easy *newhandle = duphandle(data);
     if(!newhandle) {
-      infof(data, "failed to duplicate handle\n");
+      infof(data, "failed to duplicate handle");
       rv = CURL_PUSH_DENY; /* FAIL HARD */
       goto fail;
     }
@@ -571,7 +572,7 @@ static int push_promise(struct Curl_easy *data,
     heads.data = data;
     heads.frame = frame;
     /* ask the application */
-    H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
+    H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!"));
 
     stream = data->req.p.http;
     if(!stream) {
@@ -619,7 +620,7 @@ static int push_promise(struct Curl_easy *data,
        state with the given connection !*/
     rc = Curl_multi_add_perform(data->multi, newhandle, conn);
     if(rc) {
-      infof(data, "failed to add handle to multi\n");
+      infof(data, "failed to add handle to multi");
       http2_stream_free(newhandle->req.p.http);
       newhandle->req.p.http = NULL;
       Curl_close(&newhandle);
@@ -632,15 +633,17 @@ static int push_promise(struct Curl_easy *data,
                                               frame->promised_stream_id,
                                               newhandle);
     if(rv) {
-      infof(data, "failed to set user_data for stream %d\n",
+      infof(data, "failed to set user_data for stream %d",
             frame->promised_stream_id);
       DEBUGASSERT(0);
       rv = CURL_PUSH_DENY;
       goto fail;
     }
+    Curl_dyn_init(&newstream->header_recvbuf, DYN_H2_HEADERS);
+    Curl_dyn_init(&newstream->trailer_recvbuf, DYN_H2_TRAILERS);
   }
   else {
-    H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n"));
+    H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!"));
     rv = CURL_PUSH_DENY;
   }
   fail:
@@ -676,21 +679,21 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
     /* stream ID zero is for connection-oriented stuff */
     if(frame->hd.type == NGHTTP2_SETTINGS) {
       uint32_t max_conn = httpc->settings.max_concurrent_streams;
-      H2BUGF(infof(data, "Got SETTINGS\n"));
+      H2BUGF(infof(data, "Got SETTINGS"));
       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);
-      H2BUGF(infof(data, "MAX_CONCURRENT_STREAMS == %d\n",
+      H2BUGF(infof(data, "MAX_CONCURRENT_STREAMS == %d",
                    httpc->settings.max_concurrent_streams));
-      H2BUGF(infof(data, "ENABLE_PUSH == %s\n",
+      H2BUGF(infof(data, "ENABLE_PUSH == %s",
                    httpc->settings.enable_push?"TRUE":"false"));
       if(max_conn != httpc->settings.max_concurrent_streams) {
         /* only signal change if the value actually changed */
         infof(data,
-              "Connection state changed (MAX_CONCURRENT_STREAMS == %u)!\n",
+              "Connection state changed (MAX_CONCURRENT_STREAMS == %u)!",
               httpc->settings.max_concurrent_streams);
         multi_connchanged(data->multi);
       }
@@ -700,19 +703,19 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
   if(!data_s) {
     H2BUGF(infof(data,
-                 "No Curl_easy associated with stream: %x\n",
+                 "No Curl_easy associated with stream: %x",
                  stream_id));
     return 0;
   }
 
   stream = data_s->req.p.http;
   if(!stream) {
-    H2BUGF(infof(data_s, "No proto pointer for stream: %x\n",
+    H2BUGF(infof(data_s, "No proto pointer for stream: %x",
                  stream_id));
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   }
 
-  H2BUGF(infof(data_s, "on_frame_recv() header %x stream %x\n",
+  H2BUGF(infof(data_s, "on_frame_recv() header %x stream %x",
                frame->hd.type, stream_id));
 
   switch(frame->hd.type) {
@@ -760,7 +763,8 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
            ncopy);
     stream->nread_header_recvbuf += ncopy;
 
-    H2BUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n",
+    DEBUGASSERT(stream->mem);
+    H2BUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p",
                  ncopy, stream_id, stream->mem));
 
     stream->len -= ncopy;
@@ -782,13 +786,13 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
       if(nghttp2_is_fatal(h2))
         return NGHTTP2_ERR_CALLBACK_FAILURE;
       else if(rv == CURL_PUSH_ERROROUT) {
-        DEBUGF(infof(data_s, "Fail the parent stream (too)\n"));
+        DEBUGF(infof(data_s, "Fail the parent stream (too)"));
         return NGHTTP2_ERR_CALLBACK_FAILURE;
       }
     }
     break;
   default:
-    H2BUGF(infof(data_s, "Got frame type %x for stream %u!\n",
+    H2BUGF(infof(data_s, "Got frame type %x for stream %u!",
                  frame->hd.type, stream_id));
     break;
   }
@@ -833,7 +837,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
     Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
 
   H2BUGF(infof(data_s, "%zu data received for stream %u "
-               "(%zu left in buffer %p, total %zu)\n",
+               "(%zu left in buffer %p, total %zu)",
                nread, stream_id,
                stream->len, stream->mem,
                stream->memlen));
@@ -842,7 +846,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
     stream->pausedata = mem + nread;
     stream->pauselen = len - nread;
     H2BUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
-                 ", stream %u\n",
+                 ", stream %u",
                  len - nread, stream_id));
     data_s->conn->proto.httpc.pause_stream_id = stream_id;
 
@@ -880,7 +884,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
          decided to reject stream (e.g., PUSH_PROMISE). */
       return 0;
     }
-    H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
+    H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u",
                  nghttp2_http2_strerror(error_code), error_code, stream_id));
     stream = data_s->req.p.http;
     if(!stream)
@@ -895,15 +899,15 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
     /* remove the entry from the hash as the stream is now gone */
     rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
     if(rv) {
-      infof(data_s, "http/2: failed to clear user_data for stream %d!\n",
+      infof(data_s, "http/2: failed to clear user_data for stream %d!",
             stream_id);
       DEBUGASSERT(0);
     }
     if(stream_id == httpc->pause_stream_id) {
-      H2BUGF(infof(data_s, "Stopped the pause stream!\n"));
+      H2BUGF(infof(data_s, "Stopped the pause stream!"));
       httpc->pause_stream_id = 0;
     }
-    H2BUGF(infof(data_s, "Removed stream %u hash!\n", stream_id));
+    H2BUGF(infof(data_s, "Removed stream %u hash!", stream_id));
     stream->stream_id = 0; /* cleared */
   }
   return 0;
@@ -921,7 +925,7 @@ static int on_begin_headers(nghttp2_session *session,
     return 0;
   }
 
-  H2BUGF(infof(data_s, "on_begin_headers() was called\n"));
+  H2BUGF(infof(data_s, "on_begin_headers() was called"));
 
   if(frame->hd.type != NGHTTP2_HEADERS) {
     return 0;
@@ -1049,7 +1053,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
 
   if(stream->bodystarted) {
     /* This is a trailer */
-    H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
+    H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s", namelen, name, valuelen,
                  value));
     result = Curl_dyn_addf(&stream->trailer_recvbuf,
                            "%.*s: %.*s\r\n", namelen, name,
@@ -1082,7 +1086,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
     if(get_transfer(httpc) != data_s)
       Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
 
-    H2BUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n",
+    H2BUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)",
                  stream->status_code, data_s));
     return 0;
   }
@@ -1106,7 +1110,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
   if(get_transfer(httpc) != data_s)
     Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
 
-  H2BUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
+  H2BUGF(infof(data_s, "h2 header: %.*s: %.*s", namelen, name, valuelen,
                value));
 
   return 0; /* 0 is successful */
@@ -1156,7 +1160,7 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
     return NGHTTP2_ERR_DEFERRED;
 
   H2BUGF(infof(data_s, "data_source_read_callback: "
-               "returns %zu bytes stream %u\n",
+               "returns %zu bytes stream %u",
                nread, stream_id));
 
   return nread;
@@ -1223,7 +1227,7 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
       (void)nghttp2_session_send(httpc->h2);
 
     if(http->stream_id == httpc->pause_stream_id) {
-      infof(data, "stopped the pause stream!\n");
+      infof(data, "stopped the pause stream!");
       httpc->pause_stream_id = 0;
     }
   }
@@ -1236,7 +1240,7 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
     int rv = nghttp2_session_set_stream_user_data(httpc->h2,
                                                   http->stream_id, 0);
     if(rv) {
-      infof(data, "http/2: failed to clear user_data for stream %d!\n",
+      infof(data, "http/2: failed to clear user_data for stream %d!",
             http->stream_id);
       DEBUGASSERT(0);
     }
@@ -1383,7 +1387,7 @@ static int h2_process_pending_input(struct Curl_easy *data,
   if(nread == rv) {
     H2BUGF(infof(data,
                  "h2_process_pending_input: All data in connection buffer "
-                 "processed\n"));
+                 "processed"));
     httpc->inbuflen = 0;
     httpc->nread_inbuf = 0;
   }
@@ -1391,7 +1395,7 @@ static int h2_process_pending_input(struct Curl_easy *data,
     httpc->nread_inbuf += rv;
     H2BUGF(infof(data,
                  "h2_process_pending_input: %zu bytes left in connection "
-                 "buffer\n",
+                 "buffer",
                  httpc->inbuflen - httpc->nread_inbuf));
   }
 
@@ -1412,7 +1416,7 @@ static int h2_process_pending_input(struct Curl_easy *data,
   if(should_close_session(httpc)) {
     struct HTTP *stream = data->req.p.http;
     H2BUGF(infof(data,
-                 "h2_process_pending_input: nothing to do in this session\n"));
+                 "h2_process_pending_input: nothing to do in this session"));
     if(stream->error)
       *err = CURLE_HTTP2;
     else {
@@ -1456,7 +1460,7 @@ CURLcode Curl_http2_done_sending(struct Curl_easy *data,
       struct SingleRequest *k = &data->req;
       int rv;
 
-      H2BUGF(infof(data, "HTTP/2 still wants to send data (easy %p)\n", data));
+      H2BUGF(infof(data, "HTTP/2 still wants to send data (easy %p)", data));
 
       /* and attempt to send the pending frames */
       rv = h2_session_send(data, h2);
@@ -1495,7 +1499,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
   /* Reset to FALSE to prevent infinite loop in readwrite_data function. */
   stream->closed = FALSE;
   if(stream->error == NGHTTP2_REFUSED_STREAM) {
-    H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!\n",
+    H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!",
                  stream->stream_id));
     connclose(conn, "REFUSED_STREAM"); /* don't use this anymore */
     data->state.refused_stream = TRUE;
@@ -1544,7 +1548,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
 
   stream->close_handled = TRUE;
 
-  H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
+  H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close"));
   return 0;
 }
 
@@ -1587,7 +1591,7 @@ static int h2_session_send(struct Curl_easy *data,
 
     h2_pri_spec(data, &pri_spec);
 
-    H2BUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n",
+    H2BUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)",
                  stream->stream_id, data));
     DEBUGASSERT(stream->stream_id != -1);
     rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id,
@@ -1611,7 +1615,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
 
   if(should_close_session(httpc)) {
     H2BUGF(infof(data,
-                 "http2_recv: nothing to do in this session\n"));
+                 "http2_recv: nothing to do in this session"));
     if(conn->bits.close) {
       /* already marked for closure, return OK and we're done */
       *err = CURLE_OK;
@@ -1621,10 +1625,6 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
     return -1;
   }
 
-  if(stream->closed)
-    /* closed overrides paused */
-    return http2_handle_stream_close(conn, data, stream, err);
-
   /* Nullify here because we call nghttp2_session_send() and they
      might refer to the old buffer. */
   stream->upload_mem = NULL;
@@ -1645,12 +1645,12 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
            stream->nread_header_recvbuf, ncopy);
     stream->nread_header_recvbuf += ncopy;
 
-    H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n",
+    H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf",
                  (int)ncopy));
     return ncopy;
   }
 
-  H2BUGF(infof(data, "http2_recv: easy %p (stream %u) win %u/%u\n",
+  H2BUGF(infof(data, "http2_recv: easy %p (stream %u) win %u/%u",
                data, stream->stream_id,
                nghttp2_session_get_local_window_size(httpc->h2),
                nghttp2_session_get_stream_local_window_size(httpc->h2,
@@ -1658,7 +1658,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
            ));
 
   if((data->state.drain) && stream->memlen) {
-    H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n",
+    H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)",
                  stream->memlen, stream->stream_id,
                  stream->mem, mem));
     if(mem != stream->mem) {
@@ -1686,7 +1686,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
     stream->pauselen -= nread;
 
     if(stream->pauselen == 0) {
-      H2BUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id));
+      H2BUGF(infof(data, "Unpaused by stream %u", stream->stream_id));
       DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
       httpc->pause_stream_id = 0;
 
@@ -1704,7 +1704,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
         return -1;
       }
     }
-    H2BUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n",
+    H2BUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u",
                  nread, stream->stream_id));
     return nread;
   }
@@ -1720,7 +1720,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
     if(stream->closed)
       /* closed overrides paused */
       return 0;
-    H2BUGF(infof(data, "stream %x is paused, pause id: %x\n",
+    H2BUGF(infof(data, "stream %x is paused, pause id: %x",
                  stream->stream_id, httpc->pause_stream_id));
     *err = CURLE_AGAIN;
     return -1;
@@ -1758,12 +1758,12 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
           return -1;
         }
 
-        H2BUGF(infof(data, "end of stream\n"));
+        H2BUGF(infof(data, "end of stream"));
         *err = CURLE_OK;
         return 0;
       }
 
-      H2BUGF(infof(data, "nread=%zd\n", nread));
+      H2BUGF(infof(data, "nread=%zd", nread));
 
       httpc->inbuflen = nread;
 
@@ -1772,7 +1772,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
     else {
       nread = httpc->inbuflen - httpc->nread_inbuf;
       (void)nread;  /* silence warning, used in debug */
-      H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd\n",
+      H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd",
                    nread));
     }
 
@@ -1781,14 +1781,14 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
   }
   if(stream->memlen) {
     ssize_t retlen = stream->memlen;
-    H2BUGF(infof(data, "http2_recv: returns %zd for stream %u\n",
+    H2BUGF(infof(data, "http2_recv: returns %zd for stream %u",
                  retlen, stream->stream_id));
     stream->memlen = 0;
 
     if(httpc->pause_stream_id == stream->stream_id) {
       /* data for this stream is returned now, but this stream caused a pause
          already so we need it called again asap */
-      H2BUGF(infof(data, "Data returned for PAUSED stream %u\n",
+      H2BUGF(infof(data, "Data returned for PAUSED stream %u",
                    stream->stream_id));
     }
     else if(!stream->closed) {
@@ -1803,7 +1803,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
   if(stream->closed)
     return http2_handle_stream_close(conn, data, stream, err);
   *err = CURLE_AGAIN;
-  H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
+  H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u",
                stream->stream_id));
   return -1;
 }
@@ -1907,11 +1907,11 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
 
   (void)sockindex;
 
-  H2BUGF(infof(data, "http2_send len=%zu\n", len));
+  H2BUGF(infof(data, "http2_send len=%zu", len));
 
   if(stream->stream_id != -1) {
     if(stream->close_handled) {
-      infof(data, "stream %d closed\n", stream->stream_id);
+      infof(data, "stream %d closed", stream->stream_id);
       *err = CURLE_HTTP2_STREAM;
       return -1;
     }
@@ -1940,7 +1940,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
     stream->upload_len = 0;
 
     if(should_close_session(httpc)) {
-      H2BUGF(infof(data, "http2_send: nothing to do in this session\n"));
+      H2BUGF(infof(data, "http2_send: nothing to do in this session"));
       *err = CURLE_HTTP2;
       return -1;
     }
@@ -1953,7 +1953,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
       nghttp2_session_resume_data(h2, stream->stream_id);
     }
 
-    H2BUGF(infof(data, "http2_send returns %zu for stream %u\n", len,
+    H2BUGF(infof(data, "http2_send returns %zu for stream %u", len,
                  stream->stream_id));
     return len;
   }
@@ -2116,7 +2116,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
     for(i = 0; i < nheader; ++i) {
       acc += nva[i].namelen + nva[i].valuelen;
 
-      H2BUGF(infof(data, "h2 header: %.*s:%.*s\n",
+      H2BUGF(infof(data, "h2 header: %.*s:%.*s",
                    nva[i].namelen, nva[i].name,
                    nva[i].valuelen, nva[i].value));
     }
@@ -2124,13 +2124,13 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
     if(acc > MAX_ACC) {
       infof(data, "http2_send: Warning: The cumulative length of all "
             "headers exceeds %d bytes and that could cause the "
-            "stream to be rejected.\n", MAX_ACC);
+            "stream to be rejected.", MAX_ACC);
     }
   }
 
   h2_pri_spec(data, &pri_spec);
 
-  H2BUGF(infof(data, "http2_send request allowed %d (easy handle %p)\n",
+  H2BUGF(infof(data, "http2_send request allowed %d (easy handle %p)",
                nghttp2_session_check_request_allowed(h2), (void *)data));
 
   switch(data->state.httpreq) {
@@ -2158,20 +2158,20 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
 
   if(stream_id < 0) {
     H2BUGF(infof(data,
-                 "http2_send() nghttp2_submit_request error (%s)%d\n",
+                 "http2_send() nghttp2_submit_request error (%s)%d",
                  nghttp2_strerror(stream_id), stream_id));
     *err = CURLE_SEND_ERROR;
     return -1;
   }
 
-  infof(data, "Using Stream ID: %x (easy handle %p)\n",
+  infof(data, "Using Stream ID: %x (easy handle %p)",
         stream_id, (void *)data);
   stream->stream_id = stream_id;
 
   rv = h2_session_send(data, h2);
   if(rv) {
     H2BUGF(infof(data,
-                 "http2_send() nghttp2_session_send error (%s)%d\n",
+                 "http2_send() nghttp2_session_send error (%s)%d",
                  nghttp2_strerror(rv), rv));
 
     *err = CURLE_SEND_ERROR;
@@ -2179,7 +2179,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
   }
 
   if(should_close_session(httpc)) {
-    H2BUGF(infof(data, "http2_send: nothing to do in this session\n"));
+    H2BUGF(infof(data, "http2_send: nothing to do in this session"));
     *err = CURLE_HTTP2;
     return -1;
   }
@@ -2215,6 +2215,16 @@ CURLcode Curl_http2_setup(struct Curl_easy *data,
   Curl_dyn_init(&stream->header_recvbuf, DYN_H2_HEADERS);
   Curl_dyn_init(&stream->trailer_recvbuf, DYN_H2_TRAILERS);
 
+  stream->upload_left = 0;
+  stream->upload_mem = NULL;
+  stream->upload_len = 0;
+  stream->mem = data->state.buffer;
+  stream->len = data->set.buffer_size;
+
+  multi_connchanged(data->multi);
+  /* below this point only connection related inits are done, which only needs
+     to be done once per connection */
+
   if((conn->handler == &Curl_handler_http2_ssl) ||
      (conn->handler == &Curl_handler_http2))
     return CURLE_OK; /* already done */
@@ -2230,12 +2240,11 @@ CURLcode Curl_http2_setup(struct Curl_easy *data,
     return result;
   }
 
-  infof(data, "Using HTTP2, server supports multi-use\n");
-  stream->upload_left = 0;
-  stream->upload_mem = NULL;
-  stream->upload_len = 0;
-  stream->mem = data->state.buffer;
-  stream->len = data->set.buffer_size;
+  infof(data, "Using HTTP2, server supports multiplexing");
+
+  conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+  conn->httpversion = 20;
+  conn->bundle->multiuse = BUNDLE_MULTIPLEX;
 
   httpc->inbuflen = 0;
   httpc->nread_inbuf = 0;
@@ -2243,12 +2252,7 @@ CURLcode Curl_http2_setup(struct Curl_easy *data,
   httpc->pause_stream_id = 0;
   httpc->drain_total = 0;
 
-  conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
-  conn->httpversion = 20;
-  conn->bundle->multiuse = BUNDLE_MULTIPLEX;
-
-  infof(data, "Connection state changed (HTTP/2 confirmed)\n");
-  multi_connchanged(data->multi);
+  infof(data, "Connection state changed (HTTP/2 confirmed)");
 
   return CURLE_OK;
 }
@@ -2287,7 +2291,7 @@ CURLcode Curl_http2_switched(struct Curl_easy *data,
                                               stream->stream_id,
                                               data);
     if(rv) {
-      infof(data, "http/2: failed to set user_data for stream %d!\n",
+      infof(data, "http/2: failed to set user_data for stream %d!",
             stream->stream_id);
       DEBUGASSERT(0);
     }
@@ -2327,7 +2331,7 @@ CURLcode Curl_http2_switched(struct Curl_easy *data,
   }
 
   infof(data, "Copying HTTP/2 data in stream buffer to connection buffer"
-        " after upgrade: len=%zu\n",
+        " after upgrade: len=%zu",
         nread);
 
   if(nread)
@@ -2337,15 +2341,8 @@ CURLcode Curl_http2_switched(struct Curl_easy *data,
 
   DEBUGASSERT(httpc->nread_inbuf == 0);
 
-  /* Good enough to call it an end once the remaining payload is copied to the
-   * connection buffer.
-   * Some servers (e.g. nghttpx v1.43.0) may fulfill stream 1 immediately
-   * following the protocol switch other than waiting for the client-side
-   * connection preface. If h2_process_pending_input is invoked here to parse
-   * the remaining payload, stream 1 would be marked as closed too early and
-   * thus ignored in http2_recv (following 252790c53).
-   * The logic in lib/http.c and lib/transfer.c guarantees a following
-   * http2_recv would be invoked very soon. */
+  if(-1 == h2_process_pending_input(data, httpc, &result))
+    return CURLE_HTTP2;
 
   return CURLE_OK;
 }
@@ -2378,7 +2375,7 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
     if(rv)
       return CURLE_SEND_ERROR;
 
-    DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u\n",
+    DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u",
                  window, stream->stream_id));
 
 #ifdef DEBUGBUILD
@@ -2387,7 +2384,7 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
       uint32_t window2 =
         nghttp2_session_get_stream_local_window_size(httpc->h2,
                                                      stream->stream_id);
-      DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u\n",
+      DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u",
                    window2, stream->stream_id));
     }
 #endif
index 21e2c08..d6986d9 100644 (file)
 #define DEFAULT_MAX_CONCURRENT_STREAMS 100
 
 /*
- * Store nghttp2 version info in this buffer, Prefix with a space.  Return
- * total length written.
+ * Store nghttp2 version info in this buffer.
  */
-int Curl_http2_ver(char *p, size_t len);
+void Curl_http2_ver(char *p, size_t len);
 
 const char *Curl_http2_strerror(uint32_t err);
 
index a04b46a..02663ab 100644 (file)
@@ -126,7 +126,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   tmp1 = strchr(tmp0, ':');
   len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
   if(len < 1) {
-    infof(data, "first provider can't be empty\n");
+    infof(data, "first provider can't be empty");
     ret = CURLE_BAD_FUNCTION_ARGUMENT;
     goto fail;
   }
@@ -145,7 +145,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
     tmp1 = strchr(tmp0, ':');
     len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
     if(len < 1) {
-      infof(data, "second provider can't be empty\n");
+      infof(data, "second provider can't be empty");
       ret = CURLE_BAD_FUNCTION_ARGUMENT;
       goto fail;
     }
@@ -165,7 +165,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
       tmp1 = strchr(tmp0, ':');
       len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
       if(len < 1) {
-        infof(data, "region can't be empty\n");
+        infof(data, "region can't be empty");
         ret = CURLE_BAD_FUNCTION_ARGUMENT;
         goto fail;
       }
@@ -182,7 +182,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
           goto fail;
         }
         if(strlen(service) < 1) {
-          infof(data, "service can't be empty\n");
+          infof(data, "service can't be empty");
           ret = CURLE_BAD_FUNCTION_ARGUMENT;
           goto fail;
         }
@@ -203,7 +203,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
     tmp1 = strchr(tmp0, '.');
     len = tmp1 - tmp0;
     if(!tmp1 || len < 1) {
-      infof(data, "service missing in parameters or hostname\n");
+      infof(data, "service missing in parameters or hostname");
       ret = CURLE_URL_MALFORMAT;
       goto fail;
     }
@@ -218,7 +218,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
       tmp1 = strchr(tmp0, '.');
       len = tmp1 - tmp0;
       if(!tmp1 || len < 1) {
-        infof(data, "region missing in parameters or hostname\n");
+        infof(data, "region missing in parameters or hostname");
         ret = CURLE_URL_MALFORMAT;
         goto fail;
       }
index 049b232..34bb5a8 100644 (file)
@@ -146,7 +146,8 @@ CURLcode Curl_output_digest(struct Curl_easy *data,
     tmp = strchr((char *)uripath, '?');
     if(tmp) {
       size_t urilen = tmp - (char *)uripath;
-      path = (unsigned char *) aprintf("%.*s", urilen, uripath);
+      /* typecast is fine here since the value is always less than 32 bits */
+      path = (unsigned char *) aprintf("%.*s", (int)urilen, uripath);
     }
   }
   if(!tmp)
index 68cce1b..5f764dc 100644 (file)
@@ -89,7 +89,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
   neg_ctx->havenegdata = len != 0;
   if(!len) {
     if(state == GSS_AUTHSUCC) {
-      infof(data, "Negotiate auth restarted\n");
+      infof(data, "Negotiate auth restarted");
       Curl_http_auth_cleanup_negotiate(conn);
     }
     else if(state != GSS_AUTHNONE) {
@@ -142,11 +142,11 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
   }
 
   if(neg_ctx->noauthpersist ||
-    (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) {
+     (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) {
 
     if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) {
       infof(data, "Curl_output_negotiate, "
-       "no persistent authentication: cleanup existing context");
+            "no persistent authentication: cleanup existing context");
       Curl_http_auth_cleanup_negotiate(conn);
     }
     if(!neg_ctx->context) {
index e200fdb..627a11c 100644 (file)
@@ -100,17 +100,17 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data,
     }
     else {
       if(*state == NTLMSTATE_LAST) {
-        infof(data, "NTLM auth restarted\n");
+        infof(data, "NTLM auth restarted");
         Curl_http_auth_cleanup_ntlm(conn);
       }
       else if(*state == NTLMSTATE_TYPE3) {
-        infof(data, "NTLM handshake rejected\n");
+        infof(data, "NTLM handshake rejected");
         Curl_http_auth_cleanup_ntlm(conn);
         *state = NTLMSTATE_NONE;
         return CURLE_REMOTE_ACCESS_DENIED;
       }
       else if(*state >= NTLMSTATE_TYPE1) {
-        infof(data, "NTLM handshake failure (internal error)\n");
+        infof(data, "NTLM handshake failure (internal error)");
         return CURLE_REMOTE_ACCESS_DENIED;
       }
 
index a3a62c1..58489ab 100644 (file)
@@ -61,7 +61,7 @@ static CURLcode https_proxy_connect(struct Curl_easy *data, int sockindex)
   if(!conn->bits.proxy_ssl_connected[sockindex]) {
     /* perform SSL initialization for this socket */
     result =
-      Curl_ssl_connect_nonblocking(data, conn, sockindex,
+      Curl_ssl_connect_nonblocking(data, conn, TRUE, sockindex,
                                    &conn->bits.proxy_ssl_connected[sockindex]);
     if(result)
       /* a failed connection is marked for closure to prevent (bad) re-use or
@@ -129,13 +129,13 @@ CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex)
 bool Curl_connect_complete(struct connectdata *conn)
 {
   return !conn->connect_state ||
-    (conn->connect_state->tunnel_state == TUNNEL_COMPLETE);
+    (conn->connect_state->tunnel_state >= TUNNEL_COMPLETE);
 }
 
 bool Curl_connect_ongoing(struct connectdata *conn)
 {
   return conn->connect_state &&
-    (conn->connect_state->tunnel_state != TUNNEL_COMPLETE);
+    (conn->connect_state->tunnel_state <= TUNNEL_COMPLETE);
 }
 
 /* when we've sent a CONNECT to a proxy, we should rather either wait for the
@@ -148,7 +148,7 @@ int Curl_connect_getsock(struct connectdata *conn)
   DEBUGASSERT(conn->connect_state);
   http = &conn->connect_state->http_proxy;
 
-  if(http->sending)
+  if(http->sending == HTTPSEND_REQUEST)
     return GETSOCK_WRITESOCK(0);
 
   return GETSOCK_READSOCK(0);
@@ -169,7 +169,7 @@ static CURLcode connect_init(struct Curl_easy *data, bool reinit)
     s = calloc(1, sizeof(struct http_connect_state));
     if(!s)
       return CURLE_OUT_OF_MEMORY;
-    infof(data, "allocate connect buffer!\n");
+    infof(data, "allocate connect buffer!");
     conn->connect_state = s;
     Curl_dyn_init(&s->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
 
@@ -202,13 +202,16 @@ static void connect_done(struct Curl_easy *data)
 {
   struct connectdata *conn = data->conn;
   struct http_connect_state *s = conn->connect_state;
-  s->tunnel_state = TUNNEL_COMPLETE;
-  Curl_dyn_free(&s->rcvbuf);
-  Curl_dyn_free(&s->req);
+  if(s->tunnel_state != TUNNEL_EXIT) {
+    s->tunnel_state = TUNNEL_EXIT;
+    Curl_dyn_free(&s->rcvbuf);
+    Curl_dyn_free(&s->req);
 
-  /* retore the protocol pointer */
-  data->req.p.http = s->prot_save;
-  infof(data, "CONNECT phase completed!\n");
+    /* retore the protocol pointer */
+    data->req.p.http = s->prot_save;
+    s->prot_save = NULL;
+    infof(data, "CONNECT phase completed!");
+  }
 }
 
 static CURLcode CONNECT_host(struct Curl_easy *data,
@@ -243,11 +246,11 @@ static CURLcode CONNECT_host(struct Curl_easy *data,
   return CURLE_OK;
 }
 
+#ifndef USE_HYPER
 static CURLcode CONNECT(struct Curl_easy *data,
                         int sockindex,
                         const char *hostname,
                         int remote_port)
-#ifndef USE_HYPER
 {
   int subversion = 0;
   struct SingleRequest *k = &data->req;
@@ -275,7 +278,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
       char *hostheader = NULL;
       char *host = NULL;
 
-      infof(data, "Establish HTTP proxy tunnel to %s:%d\n",
+      infof(data, "Establish HTTP proxy tunnel to %s:%d",
             hostname, remote_port);
 
         /* This only happens if we've looped here due to authentication
@@ -297,32 +300,27 @@ static CURLcode CONNECT(struct Curl_easy *data,
                                      hostheader, TRUE);
 
       if(!result) {
-        const char *proxyconn = "";
-        const char *useragent = "";
         const char *httpv =
           (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1";
 
-        if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection"))
-          proxyconn = "Proxy-Connection: Keep-Alive\r\n";
-
-        if(!Curl_checkProxyheaders(data, conn, "User-Agent") &&
-           data->set.str[STRING_USERAGENT])
-          useragent = data->state.aptr.uagent;
-
         result =
           Curl_dyn_addf(req,
                         "CONNECT %s HTTP/%s\r\n"
                         "%s"  /* Host: */
-                        "%s"  /* Proxy-Authorization */
-                        "%s"  /* User-Agent */
-                        "%s", /* Proxy-Connection */
+                        "%s", /* Proxy-Authorization */
                         hostheader,
                         httpv,
                         host?host:"",
                         data->state.aptr.proxyuserpwd?
-                        data->state.aptr.proxyuserpwd:"",
-                        useragent,
-                        proxyconn);
+                        data->state.aptr.proxyuserpwd:"");
+
+        if(!result && !Curl_checkProxyheaders(data, conn, "User-Agent") &&
+           data->set.str[STRING_USERAGENT])
+          result = Curl_dyn_addf(req, "User-Agent: %s\r\n",
+                                 data->set.str[STRING_USERAGENT]);
+
+        if(!result && !Curl_checkProxyheaders(data, conn, "Proxy-Connection"))
+          result = Curl_dyn_add(req, "Proxy-Connection: Keep-Alive\r\n");
 
         if(!result)
           result = Curl_add_custom_headers(data, TRUE, req);
@@ -387,6 +385,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
         k->upload_fromhere += bytes_written;
         return result;
       }
+      http->sending = HTTPSEND_NADA;
       /* if nothing left to send, continue */
     }
     { /* READING RESPONSE PHASE */
@@ -416,7 +415,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
             /* proxy auth was requested and there was proxy auth available,
                then deem this as "mere" proxy disconnect */
             conn->bits.proxy_connect_closed = TRUE;
-            infof(data, "Proxy CONNECT connection closed\n");
+            infof(data, "Proxy CONNECT connection closed");
           }
           else {
             error = SELECT_ERROR;
@@ -451,7 +450,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
             r = Curl_httpchunk_read(data, &byte, 1, &tookcareof, &extra);
             if(r == CHUNKE_STOP) {
               /* we're done reading chunks! */
-              infof(data, "chunk reading DONE\n");
+              infof(data, "chunk reading DONE");
               s->keepon = KEEPON_DONE;
               /* we did the full CONNECT treatment, go COMPLETE */
               s->tunnel_state = TUNNEL_COMPLETE;
@@ -510,13 +509,13 @@ static CURLcode CONNECT(struct Curl_easy *data,
 
             if(s->cl) {
               infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T
-                    " bytes of response-body\n", s->cl);
+                    " bytes of response-body", s->cl);
             }
             else if(s->chunked_encoding) {
               CHUNKcode r;
               CURLcode extra;
 
-              infof(data, "Ignore chunked response-body\n");
+              infof(data, "Ignore chunked response-body");
 
               /* We set ignorebody true here since the chunked decoder
                  function will acknowledge that. Pay attention so that this is
@@ -533,7 +532,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
                                       &extra);
               if(r == CHUNKE_STOP) {
                 /* we're done reading chunks! */
-                infof(data, "chunk reading DONE\n");
+                infof(data, "chunk reading DONE");
                 s->keepon = KEEPON_DONE;
                 /* we did the full CONNECT treatment, go to COMPLETE */
                 s->tunnel_state = TUNNEL_COMPLETE;
@@ -579,7 +578,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
             /* A client MUST ignore any Content-Length or Transfer-Encoding
                header fields received in a successful response to CONNECT.
                "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
-            infof(data, "Ignoring Content-Length in CONNECT %03d response\n",
+            infof(data, "Ignoring Content-Length in CONNECT %03d response",
                   k->httpcode);
           }
           else {
@@ -595,11 +594,11 @@ static CURLcode CONNECT(struct Curl_easy *data,
                header fields received in a successful response to CONNECT.
                "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
             infof(data, "Ignoring Transfer-Encoding in "
-                  "CONNECT %03d response\n", k->httpcode);
+                  "CONNECT %03d response", k->httpcode);
           }
           else if(Curl_compareheader(linep,
                                      "Transfer-Encoding:", "chunked")) {
-            infof(data, "CONNECT responded chunked\n");
+            infof(data, "CONNECT responded chunked");
             s->chunked_encoding = TRUE;
             /* init our chunky engine */
             Curl_httpchunk_init(data);
@@ -657,7 +656,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
   if(data->info.httpproxycode/100 != 2) {
     if(s->close_connection && data->req.newurl) {
       conn->bits.proxy_connect_closed = TRUE;
-      infof(data, "Connect me again please\n");
+      infof(data, "Connect me again please");
       connect_done(data);
     }
     else {
@@ -692,7 +691,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
   data->state.authproxy.done = TRUE;
   data->state.authproxy.multipass = FALSE;
 
-  infof(data, "Proxy replied %d to CONNECT request\n",
+  infof(data, "Proxy replied %d to CONNECT request",
         data->info.httpproxycode);
   data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */
   conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the
@@ -702,6 +701,10 @@ static CURLcode CONNECT(struct Curl_easy *data,
 }
 #else
 /* The Hyper version of CONNECT */
+static CURLcode CONNECT(struct Curl_easy *data,
+                        int sockindex,
+                        const char *hostname,
+                        int remote_port)
 {
   struct connectdata *conn = data->conn;
   struct hyptransfer *h = &data->hyp;
@@ -740,6 +743,8 @@ static CURLcode CONNECT(struct Curl_easy *data,
       hyper_io_set_write(io, Curl_hyper_send);
       conn->sockfd = tunnelsocket;
 
+      data->state.hconnect = TRUE;
+
       /* create an executor to poll futures */
       if(!h->exec) {
         h->exec = hyper_executor_new();
@@ -830,16 +835,26 @@ static CURLcode CONNECT(struct Curl_easy *data,
          Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
         goto error;
 
-      if(data->set.str[STRING_USERAGENT] &&
-         *data->set.str[STRING_USERAGENT] &&
-         data->state.aptr.uagent &&
-         Curl_hyper_header(data, headers, data->state.aptr.uagent))
-        goto error;
+      if(!Curl_checkProxyheaders(data, conn, "User-Agent") &&
+         data->set.str[STRING_USERAGENT]) {
+        struct dynbuf ua;
+        Curl_dyn_init(&ua, DYN_HTTP_REQUEST);
+        result = Curl_dyn_addf(&ua, "User-Agent: %s\r\n",
+                               data->set.str[STRING_USERAGENT]);
+        if(result)
+          goto error;
+        if(Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua)))
+          goto error;
+        Curl_dyn_free(&ua);
+      }
 
       if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection") &&
          Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
         goto error;
 
+      if(Curl_add_custom_headers(data, TRUE, headers))
+        goto error;
+
       sendtask = hyper_clientconn_send(client, req);
       if(!sendtask) {
         failf(data, "hyper_clientconn_send");
@@ -875,7 +890,6 @@ static CURLcode CONNECT(struct Curl_easy *data,
         goto error;
       if(!done)
         break;
-      fprintf(stderr, "done\n");
       s->tunnel_state = TUNNEL_COMPLETE;
       if(h->exec) {
         hyper_executor_free(h->exec);
@@ -897,6 +911,33 @@ static CURLcode CONNECT(struct Curl_easy *data,
   } while(data->req.newurl);
 
   result = CURLE_OK;
+  if(s->tunnel_state == TUNNEL_COMPLETE) {
+    data->info.httpproxycode = data->req.httpcode;
+    if(data->info.httpproxycode/100 != 2) {
+      if(conn->bits.close && data->req.newurl) {
+        conn->bits.proxy_connect_closed = TRUE;
+        infof(data, "Connect me again please");
+        connect_done(data);
+      }
+      else {
+        free(data->req.newurl);
+        data->req.newurl = NULL;
+        /* failure, close this connection to avoid re-use */
+        streamclose(conn, "proxy CONNECT failure");
+        Curl_closesocket(data, conn, conn->sock[sockindex]);
+        conn->sock[sockindex] = CURL_SOCKET_BAD;
+      }
+
+      /* to back to init state */
+      s->tunnel_state = TUNNEL_INIT;
+
+      if(!conn->bits.proxy_connect_closed) {
+        failf(data, "Received HTTP code %d from proxy after CONNECT",
+              data->req.httpcode);
+        result = CURLE_RECV_ERROR;
+      }
+    }
+  }
   error:
   free(host);
   free(hostheader);
@@ -917,7 +958,6 @@ static CURLcode CONNECT(struct Curl_easy *data,
   }
   return result;
 }
-
 #endif
 
 void Curl_connect_free(struct Curl_easy *data)
index f5a4cb0..cdf8de4 100644 (file)
@@ -65,9 +65,10 @@ struct http_connect_state {
   } keepon;
   curl_off_t cl; /* size of content to read and ignore */
   enum {
-    TUNNEL_INIT,    /* init/default/no tunnel state */
-    TUNNEL_CONNECT, /* CONNECT has been sent off */
-    TUNNEL_COMPLETE /* CONNECT response received completely */
+    TUNNEL_INIT,     /* init/default/no tunnel state */
+    TUNNEL_CONNECT,  /* CONNECT has been sent off */
+    TUNNEL_COMPLETE, /* CONNECT response received completely */
+    TUNNEL_EXIT
   } tunnel_state;
   BIT(chunked_encoding);
   BIT(close_connection);
index d85bcc3..6163899 100644 (file)
@@ -74,7 +74,6 @@
 #include "strcase.h"
 #include "vtls/vtls.h"
 #include "connect.h"
-#include "strerror.h"
 #include "select.h"
 #include "multiif.h"
 #include "url.h"
@@ -414,7 +413,7 @@ static void state(struct Curl_easy *data, imapstate newstate)
   };
 
   if(imapc->state != newstate)
-    infof(data, "IMAP %p state change from %s to %s\n",
+    infof(data, "IMAP %p state change from %s to %s",
           (void *)imapc, names[imapc->state], names[newstate]);
 #endif
 
@@ -475,8 +474,8 @@ static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data,
 {
   /* Start the SSL connection */
   struct imap_conn *imapc = &conn->proto.imapc;
-  CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
-                                                 &imapc->ssldone);
+  CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
+                                                 FIRSTSOCKET, &imapc->ssldone);
 
   if(!result) {
     if(imapc->state != IMAP_UPGRADETLS)
@@ -606,7 +605,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
       result = imap_perform_login(data, conn);
     else {
       /* Other mechanisms not supported */
-      infof(data, "No known authentication mechanisms supported!\n");
+      infof(data, "No known authentication mechanisms supported!");
       result = CURLE_LOGIN_DENIED;
     }
   }
@@ -861,7 +860,7 @@ static CURLcode imap_state_servergreet_resp(struct Curl_easy *data,
     /* PREAUTH */
     struct imap_conn *imapc = &conn->proto.imapc;
     imapc->preauth = TRUE;
-    infof(data, "PREAUTH connection, already authenticated!\n");
+    infof(data, "PREAUTH connection, already authenticated!");
   }
   else if(imapcode != IMAP_RESP_OK) {
     failf(data, "Got unexpected imap-server response");
@@ -935,22 +934,18 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data,
       line += wordlen;
     }
   }
-  else if(imapcode == IMAP_RESP_OK) {
-    if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
-      /* We don't have a SSL/TLS connection yet, but SSL is requested */
-      if(imapc->tls_supported)
-        /* Switch to TLS connection now */
-        result = imap_perform_starttls(data, conn);
-      else if(data->set.use_ssl == CURLUSESSL_TRY)
-        /* Fallback and carry on with authentication */
-        result = imap_perform_authentication(data, conn);
-      else {
-        failf(data, "STARTTLS not supported.");
-        result = CURLE_USE_SSL_FAILED;
-      }
+  else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
+    /* PREAUTH is not compatible with STARTTLS. */
+    if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
+      /* Switch to TLS connection now */
+      result = imap_perform_starttls(data, conn);
     }
-    else
+    else if(data->set.use_ssl <= CURLUSESSL_TRY)
       result = imap_perform_authentication(data, conn);
+    else {
+      failf(data, "STARTTLS not available.");
+      result = CURLE_USE_SSL_FAILED;
+    }
   }
   else
     result = imap_perform_authentication(data, conn);
@@ -968,6 +963,10 @@ static CURLcode imap_state_starttls_resp(struct Curl_easy *data,
 
   (void)instate; /* no use for this yet */
 
+  /* Pipelining in response is forbidden. */
+  if(data->conn->proto.imapc.pp.cache_size)
+    return CURLE_WEIRD_SERVER_REPLY;
+
   if(imapcode != IMAP_RESP_OK) {
     if(data->set.use_ssl != CURLUSESSL_TRY) {
       failf(data, "STARTTLS denied");
@@ -1143,7 +1142,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
   }
 
   if(parsed) {
-    infof(data, "Found %" CURL_FORMAT_CURL_OFF_T " bytes to download\n",
+    infof(data, "Found %" CURL_FORMAT_CURL_OFF_T " bytes to download",
           size);
     Curl_pgrsSetDownloadSize(data, size);
 
@@ -1169,7 +1168,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
       data->req.bytecount += chunk;
 
       infof(data, "Written %zu bytes, %" CURL_FORMAT_CURL_OFF_TU
-            " bytes are left for transfer\n", chunk, size - chunk);
+            " bytes are left for transfer", chunk, size - chunk);
 
       /* Have we used the entire cache or just part of it?*/
       if(pp->cache_size > chunk) {
@@ -1369,7 +1368,7 @@ static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done)
   struct imap_conn *imapc = &conn->proto.imapc;
 
   if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) {
-    result = Curl_ssl_connect_nonblocking(data, conn,
+    result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
                                           FIRSTSOCKET, &imapc->ssldone);
     if(result || !imapc->ssldone)
       return result;
@@ -1543,7 +1542,7 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
   struct imap_conn *imapc = &conn->proto.imapc;
   bool selected = FALSE;
 
-  DEBUGF(infof(data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts"));
 
   if(data->set.opt_no_body) {
     /* Requested no body means no transfer */
@@ -1590,7 +1589,7 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done)
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
 
   return result;
 }
@@ -1682,11 +1681,11 @@ static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done)
   CURLcode result = imap_multi_statemach(data, dophase_done);
 
   if(result)
-    DEBUGF(infof(data, "DO phase failed\n"));
+    DEBUGF(infof(data, "DO phase failed"));
   else if(*dophase_done) {
     result = imap_dophase_done(data, FALSE /* not connected */);
 
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
 
   return result;
@@ -2017,7 +2016,7 @@ static CURLcode imap_parse_url_path(struct Curl_easy *data)
       return result;
     }
 
-    DEBUGF(infof(data, "IMAP URL parameter '%s' = '%s'\n", name, value));
+    DEBUGF(infof(data, "IMAP URL parameter '%s' = '%s'", name, value));
 
     /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and
        PARTIAL) stripping of the trailing slash character if it is present.
index 4c3e9e4..b5f9b80 100644 (file)
@@ -40,7 +40,7 @@
 #define INT16SZ          2
 
 /*
- * Format an IPv4 address, more or less like inet_ntoa().
+ * Format an IPv4 address, more or less like inet_ntop().
  *
  * Returns `dst' (as a const)
  * Note:
index c8c4b66..659947d 100644 (file)
@@ -263,7 +263,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
     }
     /* We pass NULL as |output_name_type| to avoid a leak. */
     gss_display_name(&min, gssname, &output_buffer, NULL);
-    Curl_infof(data, "Trying against %s\n", output_buffer.value);
+    infof(data, "Trying against %s", output_buffer.value);
     gssresp = GSS_C_NO_BUFFER;
     *context = GSS_C_NO_CONTEXT;
 
@@ -290,7 +290,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
       }
 
       if(GSS_ERROR(maj)) {
-        Curl_infof(data, "Error creating security context\n");
+        infof(data, "Error creating security context");
         ret = AUTH_ERROR;
         break;
       }
@@ -301,8 +301,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
         result = Curl_base64_encode(data, (char *)output_buffer.value,
                                     output_buffer.length, &p, &base64_sz);
         if(result) {
-          Curl_infof(data, "base64-encoding: %s\n",
-                     curl_easy_strerror(result));
+          infof(data, "base64-encoding: %s", curl_easy_strerror(result));
           ret = AUTH_ERROR;
           break;
         }
@@ -327,7 +326,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
         }
 
         if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') {
-          Curl_infof(data, "Server didn't accept auth data\n");
+          infof(data, "Server didn't accept auth data");
           ret = AUTH_ERROR;
           break;
         }
@@ -629,7 +628,7 @@ static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
 
       socket_write(data, fd, cmd_buffer, cmd_size);
       socket_write(data, fd, "\r\n", 2);
-      infof(data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic,
+      infof(data, "Send: %s%s", prot_level == PROT_PRIVATE?enc:mic,
             cmd_buffer);
       free(cmd_buffer);
     }
@@ -738,7 +737,7 @@ static int sec_set_protection_level(struct Curl_easy *data)
 
   if(!conn->sec_complete) {
     infof(data, "Trying to change the protection level after the"
-                " completion of the data exchange.\n");
+                " completion of the data exchange.");
     return -1;
   }
 
@@ -815,13 +814,13 @@ static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
   if(mech->init) {
     ret = mech->init(conn->app_data);
     if(ret) {
-      infof(data, "Failed initialization for %s. Skipping it.\n",
+      infof(data, "Failed initialization for %s. Skipping it.",
             mech->name);
       return CURLE_FAILED_INIT;
     }
   }
 
-  infof(data, "Trying mechanism %s...\n", mech->name);
+  infof(data, "Trying mechanism %s...", mech->name);
   ret = ftp_send_command(data, "AUTH %s", mech->name);
   if(ret < 0)
     return CURLE_COULDNT_CONNECT;
@@ -830,15 +829,15 @@ static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
     switch(ret) {
     case 504:
       infof(data, "Mechanism %s is not supported by the server (server "
-            "returned ftp code: 504).\n", mech->name);
+            "returned ftp code: 504).", mech->name);
       break;
     case 534:
       infof(data, "Mechanism %s was rejected by the server (server returned "
-            "ftp code: 534).\n", mech->name);
+            "ftp code: 534).", mech->name);
       break;
     default:
       if(ret/100 == 5) {
-        infof(data, "server does not support the security extensions\n");
+        infof(data, "server does not support the security extensions");
         return CURLE_USE_SSL_FAILED;
       }
       break;
index ed16423..1d9e44c 100644 (file)
@@ -296,9 +296,9 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
   char *passwd = NULL;
 
   *done = TRUE; /* unconditionally */
-  infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n",
+  infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d",
           LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
-  infof(data, "LDAP local: %s\n", data->state.url);
+  infof(data, "LDAP local: %s", data->state.url);
 
 #ifdef HAVE_LDAP_URL_PARSE
   rc = ldap_url_parse(data->state.url, &ludp);
@@ -314,7 +314,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
   /* 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",
+  infof(data, "LDAP local: trying to establish %s connection",
           ldap_ssl ? "encrypted" : "cleartext");
 
 #if defined(USE_WIN32_LDAP)
@@ -366,14 +366,14 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
         result = CURLE_SSL_CERTPROBLEM;
         goto quit;
       }
-      infof(data, "LDAP local: using %s CA cert '%s'\n",
-              (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
-              ldap_ca);
+      infof(data, "LDAP local: using %s CA cert '%s'",
+            (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
+            ldap_ca);
       rc = ldapssl_add_trusted_cert(ldap_ca, cert_type);
       if(rc != LDAP_SUCCESS) {
         failf(data, "LDAP local: ERROR setting %s CA cert: %s",
-                (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
-                ldap_err2string(rc));
+              (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
+              ldap_err2string(rc));
         result = CURLE_SSL_CERTPROBLEM;
         goto quit;
       }
@@ -409,7 +409,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
         result = CURLE_SSL_CERTPROBLEM;
         goto quit;
       }
-      infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca);
+      infof(data, "LDAP local: using PEM CA cert: %s", ldap_ca);
       rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
       if(rc != LDAP_SUCCESS) {
         failf(data, "LDAP local: ERROR setting PEM CA cert: %s",
@@ -718,7 +718,7 @@ quit:
     LDAP_TRACE(("Received %d entries\n", num));
   }
   if(rc == LDAP_SIZELIMIT_EXCEEDED)
-    infof(data, "There are more than %d entries\n", num);
+    infof(data, "There are more than %d entries", num);
   if(ludp)
     ldap_free_urldesc(ludp);
   if(server)
index c651ddf..e7a428f 100644 (file)
 #endif /* USE_OPENSSL */
 
 #ifdef USE_MBEDTLS
-#include <mbedtls/config.h>
 #include <mbedtls/version.h>
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+#include <mbedtls/mbedtls_config.h>
+#else
+#include <mbedtls/config.h>
+#endif
 
 #if(MBEDTLS_VERSION_NUMBER >= 0x02070000)
   #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
index 7a24fd8..983ed97 100644 (file)
@@ -33,7 +33,8 @@
 #ifdef USE_MBEDTLS
 #include <mbedtls/version.h>
 
-#if(MBEDTLS_VERSION_NUMBER >= 0x02070000)
+#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \
+   (MBEDTLS_VERSION_NUMBER < 0x03000000)
   #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
 #endif
 #endif /* USE_MBEDTLS */
@@ -85,7 +86,7 @@ typedef mbedtls_md5_context MD5_CTX;
 static void MD5_Init(MD5_CTX *ctx)
 {
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
-  mbedtls_md5_starts(ctx);
+  (void) mbedtls_md5_starts(ctx);
 #else
   (void) mbedtls_md5_starts_ret(ctx);
 #endif
@@ -96,7 +97,7 @@ static void MD5_Update(MD5_CTX *ctx,
                        unsigned int length)
 {
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
-  mbedtls_md5_update(ctx, data, length);
+  (void) mbedtls_md5_update(ctx, data, length);
 #else
   (void) mbedtls_md5_update_ret(ctx, data, length);
 #endif
@@ -105,7 +106,7 @@ static void MD5_Update(MD5_CTX *ctx,
 static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
 {
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
-  mbedtls_md5_finish(ctx, digest);
+  (void) mbedtls_md5_finish(ctx, digest);
 #else
   (void) mbedtls_md5_finish_ret(ctx, digest);
 #endif
index 5292026..7a1aec5 100644 (file)
@@ -1017,9 +1017,11 @@ int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
   retcode = dprintf_formatf(&info, addbyter, format, ap_save);
   if((retcode != -1) && info.max) {
     /* we terminate this with a zero byte */
-    if(info.max == info.length)
+    if(info.max == info.length) {
       /* we're at maximum, scrap the last letter */
       info.buffer[-1] = 0;
+      retcode--; /* don't count the nul byte */
+    }
     else
       info.buffer[0] = 0;
   }
index d88fa73..fcd40b4 100644 (file)
@@ -128,6 +128,10 @@ static CURLcode mqtt_send(struct Curl_easy *data,
     mq->sendleftovers = sendleftovers;
     mq->nsend = nsend;
   }
+  else {
+    mq->sendleftovers = NULL;
+    mq->nsend = 0;
+  }
   return result;
 }
 
@@ -143,32 +147,197 @@ static int mqtt_getsock(struct Curl_easy *data,
   return GETSOCK_READSOCK(FIRSTSOCKET);
 }
 
+static int mqtt_encode_len(char *buf, size_t len)
+{
+  unsigned char encoded;
+  int i;
+
+  for(i = 0; (len > 0) && (i<4); i++) {
+    encoded = len % 0x80;
+    len /= 0x80;
+    if(len)
+      encoded |= 0x80;
+    buf[i] = encoded;
+  }
+
+  return i;
+}
+
+/* add the passwd to the CONNECT packet */
+static int add_passwd(const char *passwd, const size_t plen,
+                       char *pkt, const size_t start, int remain_pos)
+{
+  /* magic number that need to be set properly */
+  const size_t conn_flags_pos = remain_pos + 8;
+  if(plen > 0xffff)
+    return 1;
+
+  /* set password flag */
+  pkt[conn_flags_pos] |= 0x40;
+
+  /* length of password provided */
+  pkt[start] = (char)((plen >> 8) & 0xFF);
+  pkt[start + 1] = (char)(plen & 0xFF);
+  memcpy(&pkt[start + 2], passwd, plen);
+  return 0;
+}
+
+/* add user to the CONN packet */
+static int add_user(const char *username, const size_t ulen,
+                    unsigned char *pkt, const size_t start, int remain_pos)
+{
+  /* magic number that need to be set properly */
+  const size_t conn_flags_pos = remain_pos + 8;
+  if(ulen > 0xffff)
+    return 1;
+
+  /* set username flag */
+  pkt[conn_flags_pos] |= 0x80;
+  /* length of username provided */
+  pkt[start] = (unsigned char)((ulen >> 8) & 0xFF);
+  pkt[start + 1] = (unsigned char)(ulen & 0xFF);
+  memcpy(&pkt[start + 2], username, ulen);
+  return 0;
+}
+
+/* add client ID to the CONN packet */
+static int add_client_id(const char *client_id, const size_t client_id_len,
+                         char *pkt, const size_t start)
+{
+  if(client_id_len != MQTT_CLIENTID_LEN)
+    return 1;
+  pkt[start] = 0x00;
+  pkt[start + 1] = MQTT_CLIENTID_LEN;
+  memcpy(&pkt[start + 2], client_id, MQTT_CLIENTID_LEN);
+  return 0;
+}
+
+/* Set initial values of CONN packet */
+static int init_connpack(char *packet, char *remain, int remain_pos)
+{
+  /* Fixed header starts */
+  /* packet type */
+  packet[0] = MQTT_MSG_CONNECT;
+  /* remaining length field */
+  memcpy(&packet[1], remain, remain_pos);
+  /* Fixed header ends */
+
+  /* Variable header starts */
+  /* protocol length */
+  packet[remain_pos + 1] = 0x00;
+  packet[remain_pos + 2] = 0x04;
+  /* protocol name */
+  packet[remain_pos + 3] = 'M';
+  packet[remain_pos + 4] = 'Q';
+  packet[remain_pos + 5] = 'T';
+  packet[remain_pos + 6] = 'T';
+  /* protocol level */
+  packet[remain_pos + 7] = 0x04;
+  /* CONNECT flag: CleanSession */
+  packet[remain_pos + 8] = 0x02;
+  /* keep-alive 0 = disabled */
+  packet[remain_pos + 9] = 0x00;
+  packet[remain_pos + 10] = 0x3c;
+  /*end of variable header*/
+  return remain_pos + 10;
+}
+
 static CURLcode mqtt_connect(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  const size_t client_id_offset = 14;
-  const size_t packetlen = client_id_offset + MQTT_CLIENTID_LEN;
+  int pos = 0;
+  int rc = 0;
+  /*remain length*/
+  int remain_pos = 0;
+  char remain[4] = {0};
+  size_t packetlen = 0;
+  size_t payloadlen = 0;
+  size_t start_user = 0;
+  size_t start_pwd = 0;
   char client_id[MQTT_CLIENTID_LEN + 1] = "curl";
   const size_t clen = strlen("curl");
-  char packet[32] = {
-    MQTT_MSG_CONNECT,  /* packet type */
-    0x00,              /* remaining length */
-    0x00, 0x04,        /* protocol length */
-    'M','Q','T','T',   /* protocol name */
-    0x04,              /* protocol level */
-    0x02,              /* CONNECT flag: CleanSession */
-    0x00, 0x3c,        /* keep-alive 0 = disabled */
-    0x00, 0x00         /* payload1 length */
-  };
-  packet[1] = (packetlen - 2) & 0x7f;
-  packet[client_id_offset - 1] = MQTT_CLIENTID_LEN;
+  char *packet = NULL;
+
+  /* extracting username from request */
+  const char *username = data->state.aptr.user ?
+    data->state.aptr.user : "";
+  const size_t ulen = strlen(username);
+  /* extracting password from request */
+  const char *passwd = data->state.aptr.passwd ?
+    data->state.aptr.passwd : "";
+  const size_t plen = strlen(passwd);
+
+  payloadlen = ulen + plen + MQTT_CLIENTID_LEN + 2;
+  /* The plus 2 are for the MSB and LSB describing the length of the string to
+   * be added on the payload. Refer to spec 1.5.2 and 1.5.4 */
+  if(ulen)
+    payloadlen += 2;
+  if(plen)
+    payloadlen += 2;
+
+  /* getting how much occupy the remain length */
+  remain_pos = mqtt_encode_len(remain, payloadlen + 10);
+
+  /* 10 length of variable header and 1 the first byte of the fixed header */
+  packetlen = payloadlen + 10 + remain_pos + 1;
+
+  /* allocating packet */
+  if(packetlen > 268435455)
+    return CURLE_WEIRD_SERVER_REPLY;
+  packet = malloc(packetlen);
+  if(!packet)
+    return CURLE_OUT_OF_MEMORY;
+  memset(packet, 0, packetlen);
+
+  /* set initial values for CONN pack */
+  pos = init_connpack(packet, remain, remain_pos);
 
   result = Curl_rand_hex(data, (unsigned char *)&client_id[clen],
                          MQTT_CLIENTID_LEN - clen + 1);
-  memcpy(&packet[client_id_offset], client_id, MQTT_CLIENTID_LEN);
-  infof(data, "Using client id '%s'\n", client_id);
+  /* add client id */
+  rc = add_client_id(client_id, strlen(client_id), packet, pos + 1);
+  if(rc) {
+    failf(data, "Client ID length mismatched: [%lu]", strlen(client_id));
+    result = CURLE_WEIRD_SERVER_REPLY;
+    goto end;
+  }
+  infof(data, "Using client id '%s'", client_id);
+
+  /* position where starts the user payload */
+  start_user = pos + 3 + MQTT_CLIENTID_LEN;
+  /* position where starts the password payload */
+  start_pwd = start_user + ulen;
+  /* if user name was provided, add it to the packet */
+  if(ulen) {
+    start_pwd += 2;
+
+    rc = add_user(username, ulen,
+                  (unsigned char *)packet, start_user, remain_pos);
+    if(rc) {
+      failf(data, "Username is too large: [%lu]", ulen);
+      result = CURLE_WEIRD_SERVER_REPLY;
+      goto end;
+    }
+  }
+
+  /* if passwd was provided, add it to the packet */
+  if(plen) {
+    rc = add_passwd(passwd, plen, packet, start_pwd, remain_pos);
+    if(rc) {
+      failf(data, "Password is too large: [%lu]", plen);
+      result = CURLE_WEIRD_SERVER_REPLY;
+      goto end;
+    }
+  }
+
   if(!result)
     result = mqtt_send(data, packet, packetlen);
+
+end:
+  if(packet)
+    free(packet);
+  Curl_safefree(data->state.aptr.user);
+  Curl_safefree(data->state.aptr.passwd);
   return result;
 }
 
@@ -213,35 +382,12 @@ fail:
 static CURLcode mqtt_get_topic(struct Curl_easy *data,
                                char **topic, size_t *topiclen)
 {
-  CURLcode result = CURLE_OK;
   char *path = data->state.up.path;
-
-  if(strlen(path) > 1) {
-    result = Curl_urldecode(data, path + 1, 0, topic, topiclen,
-                            REJECT_NADA);
-  }
-  else {
-    failf(data, "Error: No topic specified.");
-    result = CURLE_URL_MALFORMAT;
-  }
-  return result;
-}
-
-
-static int mqtt_encode_len(char *buf, size_t len)
-{
-  unsigned char encoded;
-  int i;
-
-  for(i = 0; (len > 0) && (i<4); i++) {
-    encoded = len % 0x80;
-    len /= 0x80;
-    if(len)
-      encoded |= 0x80;
-    buf[i] = encoded;
-  }
-
-  return i;
+  if(strlen(path) > 1)
+    return Curl_urldecode(data, path + 1, 0, topic, topiclen,
+                          REJECT_NADA);
+  failf(data, "No MQTT topic found. Forgot to URL encode it?");
+  return CURLE_URL_MALFORMAT;
 }
 
 static CURLcode mqtt_subscribe(struct Curl_easy *data)
@@ -418,7 +564,7 @@ static void mqstate(struct Curl_easy *data,
   struct connectdata *conn = data->conn;
   struct mqtt_conn *mqtt = &conn->proto.mqtt;
 #ifdef CURLDEBUG
-  infof(data, "%s (from %s) (next is %s)\n",
+  infof(data, "%s (from %s) (next is %s)",
         statenames[state],
         statenames[mqtt->state],
         (state == MQTT_FIRST)? statenames[nextstate] : "");
@@ -465,7 +611,7 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
       goto MQTT_SUBACK_COMING;
     }
     else if(packet == MQTT_MSG_DISCONNECT) {
-      infof(data, "Got DISCONNECT\n");
+      infof(data, "Got DISCONNECT");
       *done = TRUE;
       goto end;
     }
@@ -476,7 +622,13 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
 
     /* -- switched state -- */
     remlen = mq->remaining_length;
-    infof(data, "Remaining length: %zd bytes\n", remlen);
+    infof(data, "Remaining length: %zd bytes", remlen);
+    if(data->set.max_filesize &&
+       (curl_off_t)remlen > data->set.max_filesize) {
+      failf(data, "Maximum file size exceeded");
+      result = CURLE_FILESIZE_EXCEEDED;
+      goto end;
+    }
     Curl_pgrsSetDownloadSize(data, remlen);
     data->req.bytecount = 0;
     data->req.size = remlen;
@@ -491,12 +643,12 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
     result = Curl_read(data, sockfd, (char *)pkt, rest, &nread);
     if(result) {
       if(CURLE_AGAIN == result) {
-        infof(data, "EEEE AAAAGAIN\n");
+        infof(data, "EEEE AAAAGAIN");
       }
       goto end;
     }
     if(!nread) {
-      infof(data, "server disconnected\n");
+      infof(data, "server disconnected");
       result = CURLE_PARTIAL_FILE;
       goto end;
     }
@@ -562,7 +714,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
       return result;
   }
 
-  infof(data, "mqtt_doing: state [%d]\n", (int) mqtt->state);
+  infof(data, "mqtt_doing: state [%d]", (int) mqtt->state);
   switch(mqtt->state) {
   case MQTT_FIRST:
     /* Read the initial byte only */
@@ -582,6 +734,10 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
       Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
       pkt[mq->npacket++] = byte;
     } while((byte & 0x80) && (mq->npacket < 4));
+    if(nread && (byte & 0x80))
+      /* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 +
+         127 * 128^3 bytes. server tried to send more */
+      result = CURLE_WEIRD_SERVER_REPLY;
     if(result)
       break;
     mq->remaining_length = mqtt_decode_len(&pkt[0], mq->npacket, NULL);
@@ -593,7 +749,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
     mqstate(data, MQTT_FIRST, MQTT_FIRST);
 
     if(mq->firstbyte == MQTT_MSG_DISCONNECT) {
-      infof(data, "Got DISCONNECT\n");
+      infof(data, "Got DISCONNECT");
       *done = TRUE;
     }
     break;
index 1b3e261..518ceb5 100644 (file)
@@ -169,7 +169,7 @@ static void mstate(struct Curl_easy *data, CURLMstate state
       connection_id = data->conn->connection_id;
 
     infof(data,
-          "STATE: %s => %s handle %p; line %d (connection #%ld)\n",
+          "STATE: %s => %s handle %p; line %d (connection #%ld)",
           statename[oldstate], statename[data->mstate],
           (void *)data, lineno, connection_id);
   }
@@ -562,7 +562,7 @@ static CURLcode multi_done(struct Curl_easy *data,
   struct connectdata *conn = data->conn;
   unsigned int i;
 
-  DEBUGF(infof(data, "multi_done\n"));
+  DEBUGF(infof(data, "multi_done"));
 
   if(data->state.done)
     /* Stop if multi_done() has already been called */
@@ -610,7 +610,7 @@ static CURLcode multi_done(struct Curl_easy *data,
     /* Stop if still used. */
     CONNCACHE_UNLOCK(data);
     DEBUGF(infof(data, "Connection still in use %zu, "
-                 "no more multi_done now!\n",
+                 "no more multi_done now!",
                  conn->easyq.size));
     return CURLE_OK;
   }
@@ -687,7 +687,7 @@ static CURLcode multi_done(struct Curl_easy *data,
     if(Curl_conncache_return_conn(data, conn)) {
       /* remember the most recently used connection */
       data->state.lastconnect_id = conn->connection_id;
-      infof(data, "%s\n", buffer);
+      infof(data, "%s", buffer);
     }
     else
       data->state.lastconnect_id = -1;
@@ -709,7 +709,6 @@ static int close_connect_only(struct Curl_easy *data,
     return 1;
 
   connclose(conn, "Removing connect-only easy handle");
-  conn->bits.connect_only = FALSE;
 
   return 1;
 }
@@ -1043,16 +1042,27 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
 
   data = multi->easyp;
   while(data) {
-    int bitmap = multi_getsock(data, sockbunch);
+    int bitmap;
+#ifdef __clang_analyzer_
+    /* to prevent "The left operand of '>=' is a garbage value" warnings */
+    memset(sockbunch, 0, sizeof(sockbunch));
+#endif
+    bitmap = multi_getsock(data, sockbunch);
 
     for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
       curl_socket_t s = CURL_SOCKET_BAD;
 
-      if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+      if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK(sockbunch[i])) {
+        if(!FDSET_SOCK(sockbunch[i]))
+          /* pretend it doesn't exist */
+          continue;
         FD_SET(sockbunch[i], read_fd_set);
         s = sockbunch[i];
       }
-      if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+      if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK(sockbunch[i])) {
+        if(!FDSET_SOCK(sockbunch[i]))
+          /* pretend it doesn't exist */
+          continue;
         FD_SET(sockbunch[i], write_fd_set);
         s = sockbunch[i];
       }
@@ -1096,6 +1106,9 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
   WSANETWORKEVENTS wsa_events;
   DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
 #endif
+#ifndef ENABLE_WAKEUP
+  (void)use_wakeup;
+#endif
 
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
@@ -1176,7 +1189,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
 #ifdef USE_WINSOCK
         long mask = 0;
 #endif
-        if(bitmap & GETSOCK_READSOCK(i)) {
+        if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
           s = sockbunch[i];
 #ifdef USE_WINSOCK
           mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
@@ -1185,7 +1198,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
           ufds[nfds].events = POLLIN;
           ++nfds;
         }
-        if(bitmap & GETSOCK_WRITESOCK(i)) {
+        if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
           s = sockbunch[i];
 #ifdef USE_WINSOCK
           mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
@@ -1540,6 +1553,58 @@ static CURLcode multi_do_more(struct Curl_easy *data, int *complete)
 }
 
 /*
+ * Check whether a timeout occurred, and handle it if it did
+ */
+static bool multi_handle_timeout(struct Curl_easy *data,
+                                 struct curltime *now,
+                                 bool *stream_error,
+                                 CURLcode *result,
+                                 bool connect_timeout)
+{
+  timediff_t timeout_ms;
+  timeout_ms = Curl_timeleft(data, now, connect_timeout);
+
+  if(timeout_ms < 0) {
+    /* Handle timed out */
+    if(data->mstate == MSTATE_RESOLVING)
+      failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
+            " milliseconds",
+            Curl_timediff(*now, data->progress.t_startsingle));
+    else if(data->mstate == MSTATE_CONNECTING)
+      failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
+            " milliseconds",
+            Curl_timediff(*now, data->progress.t_startsingle));
+    else {
+      struct SingleRequest *k = &data->req;
+      if(k->size != -1) {
+        failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+              " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
+              CURL_FORMAT_CURL_OFF_T " bytes received",
+              Curl_timediff(*now, data->progress.t_startsingle),
+              k->bytecount, k->size);
+      }
+      else {
+        failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+              " milliseconds with %" CURL_FORMAT_CURL_OFF_T
+              " bytes received",
+              Curl_timediff(*now, data->progress.t_startsingle),
+              k->bytecount);
+      }
+    }
+
+    /* Force connection closed if the connection has indeed been used */
+    if(data->mstate > MSTATE_DO) {
+      streamclose(data->conn, "Disconnected with pending data");
+      *stream_error = TRUE;
+    }
+    *result = CURLE_OPERATION_TIMEDOUT;
+    (void)multi_done(data, *result, TRUE);
+  }
+
+  return (timeout_ms < 0);
+}
+
+/*
  * We are doing protocol-specific connecting and this is being called over and
  * over from the multi interface until the connection phase is done on
  * protocol layer.
@@ -1670,7 +1735,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
   bool done = FALSE;
   CURLMcode rc;
   CURLcode result = CURLE_OK;
-  timediff_t timeout_ms;
   timediff_t recv_timeout_ms;
   timediff_t send_timeout_ms;
   int control;
@@ -1685,7 +1749,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     rc = CURLM_OK;
 
     if(multi_ischanged(multi, TRUE)) {
-      DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
+      DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!"));
       process_pending_handles(multi); /* multiplexed */
     }
 
@@ -1700,47 +1764,16 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     if(data->conn &&
        (data->mstate >= MSTATE_CONNECT) &&
        (data->mstate < MSTATE_COMPLETED)) {
+      /* Check for overall operation timeout here but defer handling the
+       * connection timeout to later, to allow for a connection to be set up
+       * in the window since we last checked timeout. This prevents us
+       * tearing down a completed connection in the case where we were slow
+       * to check the timeout (e.g. process descheduled during this loop).
+       * We set connect_timeout=FALSE to do this. */
+
       /* we need to wait for the connect state as only then is the start time
          stored, but we must not check already completed handles */
-      timeout_ms = Curl_timeleft(data, nowp,
-                                 (data->mstate <= MSTATE_DO)?
-                                 TRUE:FALSE);
-
-      if(timeout_ms < 0) {
-        /* Handle timed out */
-        if(data->mstate == MSTATE_RESOLVING)
-          failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
-                " milliseconds",
-                Curl_timediff(*nowp, data->progress.t_startsingle));
-        else if(data->mstate == MSTATE_CONNECTING)
-          failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
-                " milliseconds",
-                Curl_timediff(*nowp, data->progress.t_startsingle));
-        else {
-          struct SingleRequest *k = &data->req;
-          if(k->size != -1) {
-            failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
-                  " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
-                  CURL_FORMAT_CURL_OFF_T " bytes received",
-                  Curl_timediff(*nowp, data->progress.t_startsingle),
-                  k->bytecount, k->size);
-          }
-          else {
-            failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
-                  " milliseconds with %" CURL_FORMAT_CURL_OFF_T
-                  " bytes received",
-                  Curl_timediff(*nowp, data->progress.t_startsingle),
-                  k->bytecount);
-          }
-        }
-
-        /* Force connection closed if the connection has indeed been used */
-        if(data->mstate > MSTATE_DO) {
-          streamclose(data->conn, "Disconnected with pending data");
-          stream_error = TRUE;
-        }
-        result = CURLE_OPERATION_TIMEDOUT;
-        (void)multi_done(data, result, TRUE);
+      if(multi_handle_timeout(data, nowp, &stream_error, &result, FALSE)) {
         /* Skip the statemachine and go directly to error handling section. */
         goto statemachine_end;
       }
@@ -1792,7 +1825,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       }
       else if(data->state.previouslypending) {
         /* this transfer comes from the pending queue so try move another */
-        infof(data, "Transfer was pending, now try another\n");
+        infof(data, "Transfer was pending, now try another");
         process_pending_handles(data->multi);
       }
 
@@ -1847,7 +1880,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         data->state.async.done = TRUE;
 #endif
         result = CURLE_OK;
-        infof(data, "Hostname '%s' was found in DNS cache\n", hostname);
+        infof(data, "Hostname '%s' was found in DNS cache", hostname);
       }
 
       if(!dns)
@@ -2279,7 +2312,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         CURLcode ret = Curl_retry_request(data, &newurl);
 
         if(!ret) {
-          infof(data, "Downgrades to HTTP/1.1!\n");
+          infof(data, "Downgrades to HTTP/1.1!");
           streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
           data->state.httpwant = CURL_HTTP_VERSION_1_1;
           /* clear the error message bit too as we ignore the one we got */
@@ -2418,6 +2451,21 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     default:
       return CURLM_INTERNAL_ERROR;
     }
+
+    if(data->conn &&
+       data->mstate >= MSTATE_CONNECT &&
+       data->mstate < MSTATE_DO &&
+       rc != CURLM_CALL_MULTI_PERFORM &&
+       !multi_ischanged(multi, false)) {
+      /* We now handle stream timeouts if and only if this will be the last
+       * loop iteration. We only check this on the last iteration to ensure
+       * that if we know we have additional work to do immediately
+       * (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
+       * declaring the connection timed out as we may almost have a completed
+       * connection. */
+      multi_handle_timeout(data, nowp, &stream_error, &result, TRUE);
+    }
+
     statemachine_end:
 
     if(data->mstate < MSTATE_COMPLETED) {
@@ -3339,7 +3387,7 @@ void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
     rc = Curl_splayremove(multi->timetree, &data->state.timenode,
                           &multi->timetree);
     if(rc)
-      infof(data, "Internal error removing splay node = %d\n", rc);
+      infof(data, "Internal error removing splay node = %d", rc);
   }
 
   /* Indicate that we are in the splay tree and insert the new timer expiry
@@ -3386,7 +3434,7 @@ void Curl_expire_clear(struct Curl_easy *data)
     rc = Curl_splayremove(multi->timetree, &data->state.timenode,
                           &multi->timetree);
     if(rc)
-      infof(data, "Internal error clearing splay node = %d\n", rc);
+      infof(data, "Internal error clearing splay node = %d", rc);
 
     /* flush the timeout list too */
     while(list->size > 0) {
@@ -3394,7 +3442,7 @@ void Curl_expire_clear(struct Curl_easy *data)
     }
 
 #ifdef DEBUGBUILD
-    infof(data, "Expire cleared (transfer %p)\n", data);
+    infof(data, "Expire cleared (transfer %p)", data);
 #endif
     nowp->tv_sec = 0;
     nowp->tv_usec = 0;
index 96b8474..2e4a6ff 100644 (file)
@@ -153,6 +153,9 @@ struct Curl_multi {
   bool recheckstate; /* see Curl_multi_connchanged */
   bool in_callback;            /* true while executing a callback */
   bool ipv6_works;
+#ifdef USE_OPENSSL
+  bool ssl_seeded;
+#endif
 };
 
 #endif /* HEADER_CURL_MULTIHANDLE_H */
index 13610bb..0a4ae2c 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -42,7 +42,8 @@
 enum host_lookup_state {
   NOTHING,
   HOSTFOUND,    /* the 'machine' keyword was found */
-  HOSTVALID     /* this is "our" machine! */
+  HOSTVALID,    /* this is "our" machine! */
+  MACDEF
 };
 
 #define NETRC_FILE_MISSING 1
@@ -84,12 +85,17 @@ static int parsenetrc(const char *host,
     int  netrcbuffsize = (int)sizeof(netrcbuffer);
 
     while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
+      if(state == MACDEF) {
+        if((netrcbuffer[0] == '\n') || (netrcbuffer[0] == '\r'))
+          state = NOTHING;
+        else
+          continue;
+      }
       tok = strtok_r(netrcbuffer, " \t\n", &tok_buf);
       if(tok && *tok == '#')
         /* treat an initial hash as a comment line */
         continue;
       while(tok) {
-
         if((login && *login) && (password && *password)) {
           done = TRUE;
           break;
@@ -97,7 +103,13 @@ static int parsenetrc(const char *host,
 
         switch(state) {
         case NOTHING:
-          if(strcasecompare("machine", tok)) {
+          if(strcasecompare("macdef", tok)) {
+            /* Define a macro. A macro is defined with the specified name; its
+               contents begin with the next .netrc line and continue until a
+               null line (consecutive new-line characters) is encountered. */
+            state = MACDEF;
+          }
+          else if(strcasecompare("machine", tok)) {
             /* the next tok is the machine name, this is in itself the
                delimiter that starts the stuff entered for this machine,
                after this we need to search for 'login' and
@@ -109,6 +121,11 @@ static int parsenetrc(const char *host,
             retcode = NETRC_SUCCESS; /* we did find our host */
           }
           break;
+        case MACDEF:
+          if(!strlen(tok)) {
+            state = NOTHING;
+          }
+          break;
         case HOSTFOUND:
           if(strcasecompare(host, tok)) {
             /* and yes, this is our host! */
index 932cf89..3b77ae9 100644 (file)
@@ -31,6 +31,7 @@
 #include "sendf.h"
 #include "urldata.h"
 #include "multiif.h"
+#include "strerror.h"
 
 #include "curl_memory.h"
 /* The last #include file should be: */
@@ -104,6 +105,7 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
     iconv_t *cd = &tmpcd;
     char *input_ptr, *output_ptr;
     size_t in_bytes, out_bytes, rc;
+    char ebuffer[STRERROR_LEN];
 
     /* open an iconv conversion descriptor if necessary */
     if(data)
@@ -116,7 +118,7 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
               CURL_ICONV_CODESET_OF_NETWORK,
               CURL_ICONV_CODESET_OF_HOST,
-              errno, strerror(errno));
+              errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer)));
         return CURLE_CONV_FAILED;
       }
     }
@@ -130,7 +132,7 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
     if((rc == ICONV_ERROR) || (in_bytes)) {
       failf(data,
             "The Curl_convert_to_network iconv call failed with errno %i: %s",
-            errno, strerror(errno));
+            errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer)));
       return CURLE_CONV_FAILED;
     }
 #else
@@ -170,6 +172,7 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
     iconv_t *cd = &tmpcd;
     char *input_ptr, *output_ptr;
     size_t in_bytes, out_bytes, rc;
+    char ebuffer[STRERROR_LEN];
 
     /* open an iconv conversion descriptor if necessary */
     if(data)
@@ -182,7 +185,7 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
               CURL_ICONV_CODESET_OF_HOST,
               CURL_ICONV_CODESET_OF_NETWORK,
-              errno, strerror(errno));
+              errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer)));
         return CURLE_CONV_FAILED;
       }
     }
@@ -196,7 +199,7 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
     if((rc == ICONV_ERROR) || (in_bytes)) {
       failf(data,
             "Curl_convert_from_network iconv call failed with errno %i: %s",
-            errno, strerror(errno));
+            errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer)));
       return CURLE_CONV_FAILED;
     }
 #else
@@ -237,6 +240,7 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
     char *input_ptr;
     char *output_ptr;
     size_t in_bytes, out_bytes, rc;
+    char ebuffer[STRERROR_LEN];
 
     /* open an iconv conversion descriptor if necessary */
     if(data)
@@ -249,7 +253,7 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
               CURL_ICONV_CODESET_OF_HOST,
               CURL_ICONV_CODESET_FOR_UTF8,
-              errno, strerror(errno));
+              errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer)));
         return CURLE_CONV_FAILED;
       }
     }
@@ -263,7 +267,7 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
     if((rc == ICONV_ERROR) || (in_bytes)) {
       failf(data,
             "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
-            errno, strerror(errno));
+            errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer)));
       return CURLE_CONV_FAILED;
     }
     if(output_ptr < input_ptr) {
index 0b8bc34..fb5e743 100644 (file)
@@ -247,7 +247,7 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
 #ifdef USE_SSL
   if(conn->handler->flags & PROTOPT_SSL) {
     CURLcode result;
-    result = Curl_ssl_connect_nonblocking(data, conn,
+    result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
                                           FIRSTSOCKET, &li->ssldone);
     if(result)
       return result;
@@ -270,7 +270,8 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
   if(conn->handler->flags & PROTOPT_SSL) {
     /* Is the SSL handshake complete yet? */
     if(!li->ssldone) {
-      CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
+      CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
+                                                     FIRSTSOCKET,
                                                      &li->ssldone);
       if(result || !li->ssldone)
         return result;
@@ -399,7 +400,7 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done)
 
   connkeep(conn, "OpenLDAP do");
 
-  infof(data, "LDAP local: %s\n", data->state.url);
+  infof(data, "LDAP local: %s", data->state.url);
 
   rc = ldap_url_parse(data->state.url, &ludp);
   if(rc != LDAP_URL_SUCCESS) {
@@ -509,7 +510,7 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
       else {
         /* successful */
         if(code == LDAP_SIZELIMIT_EXCEEDED)
-          infof(data, "There are more than %d entries\n", lr->nument);
+          infof(data, "There are more than %d entries", lr->nument);
         data->req.size = data->req.bytecount;
         *err = CURLE_OK;
         ret = 0;
index 4811739..84c7f51 100644 (file)
@@ -402,7 +402,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
         clipamount = gotbytes - i;
         restart = TRUE;
         DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing "
-                     "server response left\n",
+                     "server response left",
                      (int)clipamount));
       }
       else if(keepon) {
@@ -412,7 +412,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
              with it. We keep the first bytes of the line then we throw
              away the rest. */
           infof(data, "Excessive server response line length received, "
-                "%zd bytes. Stripping\n", gotbytes);
+                "%zd bytes. Stripping", gotbytes);
           restart = TRUE;
 
           /* we keep 40 bytes since all our pingpong protocols are only
index 9b6ea64..d3f3de6 100644 (file)
@@ -75,7 +75,6 @@
 #include "strcase.h"
 #include "vtls/vtls.h"
 #include "connect.h"
-#include "strerror.h"
 #include "select.h"
 #include "multiif.h"
 #include "url.h"
@@ -308,7 +307,7 @@ static void state(struct Curl_easy *data, pop3state newstate)
   };
 
   if(pop3c->state != newstate)
-    infof(data, "POP3 %p state change from %s to %s\n",
+    infof(data, "POP3 %p state change from %s to %s",
           (void *)pop3c, names[pop3c->state], names[newstate]);
 #endif
 
@@ -370,8 +369,9 @@ static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data,
 {
   /* Start the SSL connection */
   struct pop3_conn *pop3c = &conn->proto.pop3c;
-  CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
-                                                 &pop3c->ssldone);
+  CURLcode result =
+    Curl_ssl_connect_nonblocking(data, conn, FALSE, FIRSTSOCKET,
+                                 &pop3c->ssldone);
 
   if(!result) {
     if(pop3c->state != POP3_UPGRADETLS)
@@ -551,7 +551,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data,
       result = pop3_perform_user(data, conn);
     else {
       /* Other mechanisms not supported */
-      infof(data, "No known authentication mechanisms supported!\n");
+      infof(data, "No known authentication mechanisms supported!");
       result = CURLE_LOGIN_DENIED;
     }
   }
@@ -740,28 +740,23 @@ static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code,
       }
     }
   }
-  else if(pop3code == '+') {
-    if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
-      /* We don't have a SSL/TLS connection yet, but SSL is requested */
-      if(pop3c->tls_supported)
-        /* Switch to TLS connection now */
-        result = pop3_perform_starttls(data, conn);
-      else if(data->set.use_ssl == CURLUSESSL_TRY)
-        /* Fallback and carry on with authentication */
-        result = pop3_perform_authentication(data, conn);
-      else {
-        failf(data, "STLS not supported.");
-        result = CURLE_USE_SSL_FAILED;
-      }
-    }
-    else
-      result = pop3_perform_authentication(data, conn);
-  }
   else {
     /* Clear text is supported when CAPA isn't recognised */
-    pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
+    if(pop3code != '+')
+      pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
 
-    result = pop3_perform_authentication(data, conn);
+    if(!data->set.use_ssl || conn->ssl[FIRSTSOCKET].use)
+      result = pop3_perform_authentication(data, conn);
+    else if(pop3code == '+' && pop3c->tls_supported)
+      /* Switch to TLS connection now */
+      result = pop3_perform_starttls(data, conn);
+    else if(data->set.use_ssl <= CURLUSESSL_TRY)
+      /* Fallback and carry on with authentication */
+      result = pop3_perform_authentication(data, conn);
+    else {
+      failf(data, "STLS not supported.");
+      result = CURLE_USE_SSL_FAILED;
+    }
   }
 
   return result;
@@ -776,6 +771,10 @@ static CURLcode pop3_state_starttls_resp(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   (void)instate; /* no use for this yet */
 
+  /* Pipelining in response is forbidden. */
+  if(data->conn->proto.pop3c.pp.cache_size)
+    return CURLE_WEIRD_SERVER_REPLY;
+
   if(pop3code != '+') {
     if(data->set.use_ssl != CURLUSESSL_TRY) {
       failf(data, "STARTTLS denied");
@@ -1031,7 +1030,7 @@ static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done)
   struct pop3_conn *pop3c = &conn->proto.pop3c;
 
   if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
-    result = Curl_ssl_connect_nonblocking(data, conn,
+    result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
                                           FIRSTSOCKET, &pop3c->ssldone);
     if(result || !pop3c->ssldone)
       return result;
@@ -1172,7 +1171,7 @@ static CURLcode pop3_perform(struct Curl_easy *data, bool *connected,
   struct connectdata *conn = data->conn;
   struct POP3 *pop3 = data->req.p.pop3;
 
-  DEBUGF(infof(data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts"));
 
   if(data->set.opt_no_body) {
     /* Requested no body means no transfer */
@@ -1191,7 +1190,7 @@ static CURLcode pop3_perform(struct Curl_easy *data, bool *connected,
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done)
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
 
   return result;
 }
@@ -1274,11 +1273,11 @@ static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done)
   CURLcode result = pop3_multi_statemach(data, dophase_done);
 
   if(result)
-    DEBUGF(infof(data, "DO phase failed\n"));
+    DEBUGF(infof(data, "DO phase failed"));
   else if(*dophase_done) {
     result = pop3_dophase_done(data, FALSE /* not connected */);
 
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
 
   return result;
index 4bcd615..f5ef6bd 100644 (file)
@@ -377,7 +377,12 @@ static curl_off_t trspeed(curl_off_t size, /* number of bytes */
 {
   if(us < 1)
     return size * 1000000;
-  return (curl_off_t)((long double)size/us * 1000000);
+  else if(size < CURL_OFF_T_MAX/1000000)
+    return (size * 1000000) / us;
+  else if(us >= 1000000)
+    return size / (us / 1000000);
+  else
+    return CURL_OFF_T_MAX;
 }
 
 /* returns TRUE if it's time to show the progress meter */
index 947f13e..b030359 100644 (file)
@@ -45,7 +45,7 @@ CURLcode Curl_quic_is_connected(struct Curl_easy *data,
                                 struct connectdata *conn,
                                 int sockindex,
                                 bool *connected);
-int Curl_quic_ver(char *p, size_t len);
+void Curl_quic_ver(char *p, size_t len);
 CURLcode Curl_quic_done_sending(struct Curl_easy *data);
 void Curl_quic_done(struct Curl_easy *data, bool premature);
 bool Curl_quic_data_pending(const struct Curl_easy *data);
index 951fedb..8f2c1ba 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -87,7 +87,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
 
   if(!seeded) {
     struct curltime now = Curl_now();
-    infof(data, "WARNING: Using weak random seed\n");
+    infof(data, "WARNING: Using weak random seed");
     randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
     randseed = randseed * 1103515245 + 12345;
     randseed = randseed * 1103515245 + 12345;
index 007d5c5..30fefb9 100644 (file)
@@ -231,7 +231,7 @@ static CURLcode rtsp_done(struct Curl_easy *data,
     }
     if(data->set.rtspreq == RTSPREQ_RECEIVE &&
             (data->conn->proto.rtspc.rtp_channel == -1)) {
-      infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv);
+      infof(data, "Got an RTP Receive with a CSeq of %ld", CSeq_recv);
     }
   }
 
@@ -651,7 +651,7 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
       }
       /* We have the full RTP interleaved packet
        * Write out the header including the leading '$' */
-      DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n",
+      DEBUGF(infof(data, "RTP write channel %d rtp_length %d",
              rtspc->rtp_channel, rtp_length));
       result = rtp_client_write(data, &rtp[0], rtp_length + 4);
       if(result) {
@@ -682,7 +682,7 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
   }
 
   if(rtp_dataleft && rtp[0] == '$') {
-    DEBUGF(infof(data, "RTP Rewinding %zd %s\n", rtp_dataleft,
+    DEBUGF(infof(data, "RTP Rewinding %zd %s", rtp_dataleft,
           *readmore ? "(READMORE)" : ""));
 
     /* Store the incomplete RTP packet for a "rewind" */
index 1e9cb7d..da11ade 100644 (file)
@@ -22,7 +22,7 @@
  *
  ***************************************************************************/
 #ifdef USE_HYPER
-#define CURL_DISABLE_RTSP
+#define CURL_DISABLE_RTSP 1
 #endif
 
 #ifndef CURL_DISABLE_RTSP
index 4db6487..59a571d 100644 (file)
@@ -97,8 +97,10 @@ int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
 #if defined(TPF)
 #define VALID_SOCK(x) 1
 #define VERIFY_SOCK(x) Curl_nop_stmt
+#define FDSET_SOCK(x) 1
 #elif defined(USE_WINSOCK)
 #define VALID_SOCK(s) ((s) < INVALID_SOCKET)
+#define FDSET_SOCK(x) 1
 #define VERIFY_SOCK(x) do { \
   if(!VALID_SOCK(x)) { \
     SET_SOCKERRNO(WSAEINVAL); \
@@ -106,13 +108,17 @@ int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
   } \
 } while(0)
 #else
-#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
-#define VERIFY_SOCK(x) do { \
-  if(!VALID_SOCK(x)) { \
-    SET_SOCKERRNO(EINVAL); \
-    return -1; \
-  } \
-} while(0)
+#define VALID_SOCK(s) ((s) >= 0)
+
+/* If the socket is small enough to get set or read from an fdset */
+#define FDSET_SOCK(s) ((s) < FD_SETSIZE)
+
+#define VERIFY_SOCK(x) do {                     \
+    if(!VALID_SOCK(x) || !FDSET_SOCK(x)) {      \
+      SET_SOCKERRNO(EINVAL);                    \
+      return -1;                                \
+    }                                           \
+  } while(0)
 #endif
 
 #endif /* HEADER_CURL_SELECT_H */
index e41bb80..14ca84b 100644 (file)
@@ -236,29 +236,21 @@ bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
 #endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
 
 /* Curl_infof() is for info message along the way */
+#define MAXINFO 2048
 
 void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
 {
+  DEBUGASSERT(!strchr(fmt, '\n'));
   if(data && data->set.verbose) {
     va_list ap;
     size_t len;
-    char print_buffer[2048 + 1];
+    char buffer[MAXINFO + 2];
     va_start(ap, fmt);
-    len = mvsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
-    /*
-     * Indicate truncation of the input by replacing the last 3 characters
-     * with "...", and transfer the newline over in case the format had one.
-     */
-    if(len >= sizeof(print_buffer)) {
-      len = strlen(fmt);
-      if(fmt[--len] == '\n')
-        msnprintf(print_buffer + (sizeof(print_buffer) - 5), 5, "...\n");
-      else
-        msnprintf(print_buffer + (sizeof(print_buffer) - 4), 4, "...");
-    }
+    len = mvsnprintf(buffer, MAXINFO, fmt, ap);
     va_end(ap);
-    len = strlen(print_buffer);
-    Curl_debug(data, CURLINFO_TEXT, print_buffer, len);
+    buffer[len++] = '\n';
+    buffer[len] = '\0';
+    Curl_debug(data, CURLINFO_TEXT, buffer, len);
   }
 }
 
@@ -274,14 +266,14 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
     size_t len;
     char error[CURL_ERROR_SIZE + 2];
     va_start(ap, fmt);
-    (void)mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
-    len = strlen(error);
+    len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
 
     if(data->set.errorbuffer && !data->state.errorbuf) {
       strcpy(data->set.errorbuffer, error);
       data->state.errorbuf = TRUE; /* wrote error string */
     }
     error[len++] = '\n';
+    error[len] = '\0';
     Curl_debug(data, CURLINFO_TEXT, error, len);
     va_end(ap);
   }
index fb8b86d..08827d1 100644 (file)
@@ -1689,7 +1689,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
   case CURLOPT_SSLCERT_BLOB:
     /*
-     * Blob that holds file name of the SSL certificate to use
+     * Blob that holds file content of the SSL certificate to use
      */
     result = Curl_setblobopt(&data->set.blobs[BLOB_CERT],
                              va_arg(param, struct curl_blob *));
@@ -1704,7 +1704,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
   case CURLOPT_PROXY_SSLCERT_BLOB:
     /*
-     * Blob that holds file name of the SSL certificate to use for proxy
+     * Blob that holds file content of the SSL certificate to use for proxy
      */
     result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY],
                              va_arg(param, struct curl_blob *));
@@ -1735,7 +1735,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
   case CURLOPT_SSLKEY_BLOB:
     /*
-     * Blob that holds file name of the SSL key to use
+     * Blob that holds file content of the SSL key to use
      */
     result = Curl_setblobopt(&data->set.blobs[BLOB_KEY],
                              va_arg(param, struct curl_blob *));
@@ -1750,7 +1750,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
   case CURLOPT_PROXY_SSLKEY_BLOB:
     /*
-     * Blob that holds file name of the SSL key to use for proxy
+     * Blob that holds file content of the SSL key to use for proxy
      */
     result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY],
                              va_arg(param, struct curl_blob *));
@@ -1872,7 +1872,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
   case CURLOPT_DOH_SSL_VERIFYPEER:
     /*
-     * Enable peer SSL verifying for DOH.
+     * Enable peer SSL verifying for DoH.
      */
     data->set.doh_verifypeer = (0 != va_arg(param, long)) ?
       TRUE : FALSE;
@@ -1911,7 +1911,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
   case CURLOPT_DOH_SSL_VERIFYHOST:
     /*
-     * Enable verification of the host name in the peer certificate for DOH
+     * Enable verification of the host name in the peer certificate for DoH
      */
     arg = va_arg(param, long);
 
@@ -1955,7 +1955,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
   case CURLOPT_DOH_SSL_VERIFYSTATUS:
     /*
-     * Enable certificate status verifying for DOH.
+     * Enable certificate status verifying for DoH.
      */
     if(!Curl_ssl_cert_status_request()) {
       result = CURLE_NOT_BUILT_IN;
index c34f97e..a2e7e41 100644 (file)
@@ -42,8 +42,9 @@
 #ifdef USE_MBEDTLS
 #include <mbedtls/version.h>
 
-#if(MBEDTLS_VERSION_NUMBER >= 0x02070000)
-  #define HAS_RESULT_CODE_BASED_FUNCTIONS
+#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \
+   (MBEDTLS_VERSION_NUMBER < 0x03000000)
+  #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
 #endif
 #endif /* USE_MBEDTLS */
 
@@ -105,8 +106,8 @@ typedef mbedtls_sha256_context SHA256_CTX;
 
 static void SHA256_Init(SHA256_CTX *ctx)
 {
-#if !defined(HAS_RESULT_CODE_BASED_FUNCTIONS)
-  mbedtls_sha256_starts(ctx, 0);
+#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
+  (void) mbedtls_sha256_starts(ctx, 0);
 #else
   (void) mbedtls_sha256_starts_ret(ctx, 0);
 #endif
@@ -116,8 +117,8 @@ static void SHA256_Update(SHA256_CTX *ctx,
                           const unsigned char *data,
                           unsigned int length)
 {
-#if !defined(HAS_RESULT_CODE_BASED_FUNCTIONS)
-  mbedtls_sha256_update(ctx, data, length);
+#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
+  (void) mbedtls_sha256_update(ctx, data, length);
 #else
   (void) mbedtls_sha256_update_ret(ctx, data, length);
 #endif
@@ -125,8 +126,8 @@ static void SHA256_Update(SHA256_CTX *ctx,
 
 static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
 {
-#if !defined(HAS_RESULT_CODE_BASED_FUNCTIONS)
-  mbedtls_sha256_finish(ctx, digest);
+#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
+  (void) mbedtls_sha256_finish(ctx, digest);
 #else
   (void) mbedtls_sha256_finish_ret(ctx, digest);
 #endif
index 39facb2..fd49cf6 100644 (file)
@@ -204,7 +204,7 @@ static void conn_state(struct Curl_easy *data, enum smb_conn_state newstate)
   };
 
   if(smbc->state != newstate)
-    infof(data, "SMB conn %p state change from %s to %s\n",
+    infof(data, "SMB conn %p state change from %s to %s",
           (void *)smbc, names[smbc->state], names[newstate]);
 #endif
 
@@ -230,7 +230,7 @@ static void request_state(struct Curl_easy *data,
   };
 
   if(req->state != newstate)
-    infof(data, "SMB request %p state change from %s to %s\n",
+    infof(data, "SMB request %p state change from %s to %s",
           (void *)req, names[req->state], names[newstate]);
 #endif
 
@@ -670,7 +670,7 @@ static CURLcode smb_connection_state(struct Curl_easy *data, bool *done)
 #ifdef USE_SSL
     if((conn->handler->flags & PROTOPT_SSL)) {
       bool ssl_done = FALSE;
-      result = Curl_ssl_connect_nonblocking(data, conn,
+      result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
                                             FIRSTSOCKET, &ssl_done);
       if(result && result != CURLE_AGAIN)
         return result;
index feffc05..02ddaca 100644 (file)
@@ -78,7 +78,6 @@
 #include "strcase.h"
 #include "vtls/vtls.h"
 #include "connect.h"
-#include "strerror.h"
 #include "select.h"
 #include "multiif.h"
 #include "url.h"
@@ -308,7 +307,7 @@ static void state(struct Curl_easy *data, smtpstate newstate)
   };
 
   if(smtpc->state != newstate)
-    infof(data, "SMTP %p state change from %s to %s\n",
+    infof(data, "SMTP %p state change from %s to %s",
           (void *)smtpc, names[smtpc->state], names[newstate]);
 #endif
 
@@ -397,7 +396,8 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data)
   /* Start the SSL connection */
   struct connectdata *conn = data->conn;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
-  CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
+  CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
+                                                 FIRSTSOCKET,
                                                  &smtpc->ssldone);
 
   if(!result) {
@@ -484,7 +484,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data)
       state(data, SMTP_AUTH);
     else {
       /* Other mechanisms not supported */
-      infof(data, "No known authentication mechanisms supported!\n");
+      infof(data, "No known authentication mechanisms supported!");
       result = CURLE_LOGIN_DENIED;
     }
   }
@@ -834,6 +834,10 @@ static CURLcode smtp_state_starttls_resp(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   (void)instate; /* no use for this yet */
 
+  /* Pipelining in response is forbidden. */
+  if(data->conn->proto.smtpc.pp.cache_size)
+    return CURLE_WEIRD_SERVER_REPLY;
+
   if(smtpcode != 220) {
     if(data->set.use_ssl != CURLUSESSL_TRY) {
       failf(data, "STARTTLS denied, code %d", smtpcode);
@@ -1258,7 +1262,7 @@ static CURLcode smtp_multi_statemach(struct Curl_easy *data, bool *done)
   struct smtp_conn *smtpc = &conn->proto.smtpc;
 
   if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
-    result = Curl_ssl_connect_nonblocking(data, conn,
+    result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
                                           FIRSTSOCKET, &smtpc->ssldone);
     if(result || !smtpc->ssldone)
       return result;
@@ -1455,7 +1459,7 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
   struct connectdata *conn = data->conn;
   struct SMTP *smtp = data->req.p.smtp;
 
-  DEBUGF(infof(data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts"));
 
   if(data->set.opt_no_body) {
     /* Requested no body means no transfer */
@@ -1495,7 +1499,7 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done)
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
 
   return result;
 }
@@ -1579,11 +1583,11 @@ static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done)
   CURLcode result = smtp_multi_statemach(data, dophase_done);
 
   if(result)
-    DEBUGF(infof(data, "DO phase failed\n"));
+    DEBUGF(infof(data, "DO phase failed"));
   else if(*dophase_done) {
     result = smtp_dophase_done(data, FALSE /* not connected */);
 
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
 
   return result;
index 2c580ad..409d2ad 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2019 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2019 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
 #endif /* !INADDR_LOOPBACK */
 #endif /* !WIN32 */
 
+#include "nonblock.h" /* for curlx_nonblock */
+#include "timeval.h"  /* needed before select.h */
+#include "select.h"   /* for Curl_poll */
+
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -59,12 +63,11 @@ int Curl_socketpair(int domain, int type, int protocol,
   union {
     struct sockaddr_in inaddr;
     struct sockaddr addr;
-  } a;
+  } a, a2;
   curl_socket_t listener;
   curl_socklen_t addrlen = sizeof(a.inaddr);
   int reuse = 1;
-  char data[2][12];
-  ssize_t dlen;
+  struct pollfd pfd[1];
   (void)domain;
   (void)type;
   (void)protocol;
@@ -85,7 +88,8 @@ int Curl_socketpair(int domain, int type, int protocol,
     goto error;
   if(bind(listener, &a.addr, sizeof(a.inaddr)) == -1)
     goto error;
-  if(getsockname(listener, &a.addr, &addrlen) == -1)
+  if(getsockname(listener, &a.addr, &addrlen) == -1 ||
+     addrlen < (int)sizeof(a.inaddr))
     goto error;
   if(listen(listener, 1) == -1)
     goto error;
@@ -94,18 +98,30 @@ int Curl_socketpair(int domain, int type, int protocol,
     goto error;
   if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1)
     goto error;
+
+  /* use non-blocking accept to make sure we don't block forever */
+  if(curlx_nonblock(listener, TRUE) < 0)
+    goto error;
+  pfd[0].fd = listener;
+  pfd[0].events = POLLIN;
+  pfd[0].revents = 0;
+  (void)Curl_poll(pfd, 1, 10*1000); /* 10 seconds */
   socks[1] = accept(listener, NULL, NULL);
   if(socks[1] == CURL_SOCKET_BAD)
     goto error;
 
   /* verify that nothing else connected */
-  msnprintf(data[0], sizeof(data[0]), "%p", socks);
-  dlen = strlen(data[0]);
-  if(swrite(socks[0], data[0], dlen) != dlen)
+  addrlen = sizeof(a.inaddr);
+  if(getsockname(socks[0], &a.addr, &addrlen) == -1 ||
+     addrlen < (int)sizeof(a.inaddr))
     goto error;
-  if(sread(socks[1], data[1], sizeof(data[1])) != dlen)
+  addrlen = sizeof(a2.inaddr);
+  if(getpeername(socks[1], &a2.addr, &addrlen) == -1 ||
+     addrlen < (int)sizeof(a2.inaddr))
     goto error;
-  if(memcmp(data[0], data[1], dlen))
+  if(a.inaddr.sin_family != a2.inaddr.sin_family ||
+     a.inaddr.sin_addr.s_addr != a2.inaddr.sin_addr.s_addr ||
+     a.inaddr.sin_port != a2.inaddr.sin_port)
     goto error;
 
   sclose(listener);
index 5cde4a4..db4c808 100644 (file)
@@ -99,24 +99,24 @@ int Curl_blockread_all(struct Curl_easy *data,   /* transfer */
 }
 #endif
 
-#ifndef DEBUGBUILD
-#define sxstate(x,y) socksstate(x,y)
-#else
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+#define DEBUG_AND_VERBOSE
 #define sxstate(x,y) socksstate(x,y, __LINE__)
+#else
+#define sxstate(x,y) socksstate(x,y)
 #endif
 
-
 /* always use this function to change state, to make debugging easier */
 static void socksstate(struct Curl_easy *data,
                        enum connect_t state
-#ifdef DEBUGBUILD
+#ifdef DEBUG_AND_VERBOSE
                        , int lineno
 #endif
 )
 {
   struct connectdata *conn = data->conn;
   enum connect_t oldstate = conn->cnnct.state;
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+#ifdef DEBUG_AND_VERBOSE
   /* synced with the state list in urldata.h */
   static const char * const statename[] = {
     "INIT",
@@ -146,9 +146,9 @@ static void socksstate(struct Curl_easy *data,
 
   conn->cnnct.state = state;
 
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+#ifdef DEBUG_AND_VERBOSE
   infof(data,
-        "SXSTATE: %s => %s conn %p; line %d\n",
+        "SXSTATE: %s => %s conn %p; line %d",
         statename[oldstate], statename[conn->cnnct.state], conn,
         lineno);
 #endif
@@ -214,10 +214,10 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
     /* SOCKS4 can only do IPv4, insist! */
     conn->ip_version = CURL_IPRESOLVE_V4;
     if(conn->bits.httpproxy)
-      infof(data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n",
+      infof(data, "SOCKS4%s: connecting to HTTP proxy %s port %d",
             protocol4a ? "a" : "", hostname, remote_port);
 
-    infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port);
+    infof(data, "SOCKS4 communication to %s:%d", hostname, remote_port);
 
     /*
      * Compose socks4 request
@@ -244,7 +244,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
         return CURLPX_RESOLVE_HOST;
       else if(rc == CURLRESOLV_PENDING) {
         sxstate(data, CONNECT_RESOLVING);
-        infof(data, "SOCKS4 non-blocking resolve of %s\n", hostname);
+        infof(data, "SOCKS4 non-blocking resolve of %s", hostname);
         return CURLPX_OK;
       }
       sxstate(data, CONNECT_RESOLVED);
@@ -264,7 +264,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
       data->state.async.dns = dns;
       data->state.async.done = TRUE;
 #endif
-      infof(data, "Hostname '%s' was found\n", hostname);
+      infof(data, "Hostname '%s' was found", hostname);
       sxstate(data, CONNECT_RESOLVED);
     }
     else {
@@ -279,18 +279,21 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
   CONNECT_RESOLVED:
   case CONNECT_RESOLVED: {
     struct Curl_addrinfo *hp = NULL;
-    char buf[64];
     /*
      * We cannot use 'hostent' as a struct that Curl_resolv() returns.  It
      * returns a Curl_addrinfo pointer that may not always look the same.
      */
-    if(dns)
+    if(dns) {
       hp = dns->addr;
-    if(hp) {
-      Curl_printable_address(hp, buf, sizeof(buf));
 
-      if(hp->ai_family == AF_INET) {
+      /* scan for the first IPv4 address */
+      while(hp && (hp->ai_family != AF_INET))
+        hp = hp->ai_next;
+
+      if(hp) {
         struct sockaddr_in *saddr_in;
+        char buf[64];
+        Curl_printable_address(hp, buf, sizeof(buf));
 
         saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
         socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0];
@@ -298,20 +301,19 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
         socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2];
         socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3];
 
-        infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)\n", buf);
-      }
-      else {
-        hp = NULL; /* fail! */
-        failf(data, "SOCKS4 connection to %s not supported", buf);
-      }
+        infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)", buf);
 
-      Curl_resolv_unlock(data, dns); /* not used anymore from now on */
+        Curl_resolv_unlock(data, dns); /* not used anymore from now on */
+      }
+      else
+        failf(data, "SOCKS4 connection to %s not supported", hostname);
     }
-    if(!hp) {
+    else
       failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
             hostname);
+
+    if(!hp)
       return CURLPX_RESOLVE_HOST;
-    }
   }
     /* FALLTHROUGH */
   CONNECT_REQ_INIT:
@@ -435,7 +437,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
   /* Result */
   switch(socksreq[1]) {
   case 90:
-    infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":"");
+    infof(data, "SOCKS4%s request granted.", protocol4a?"a":"");
     break;
   case 91:
     failf(data,
@@ -528,19 +530,19 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
   switch(sx->state) {
   case CONNECT_SOCKS_INIT:
     if(conn->bits.httpproxy)
-      infof(data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
+      infof(data, "SOCKS5: connecting to HTTP proxy %s port %d",
             hostname, remote_port);
 
     /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
     if(!socks5_resolve_local && hostname_len > 255) {
       infof(data, "SOCKS5: server resolving disabled for hostnames of "
-            "length > 255 [actual len=%zu]\n", hostname_len);
+            "length > 255 [actual len=%zu]", hostname_len);
       socks5_resolve_local = TRUE;
     }
 
     if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
       infof(data,
-            "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n",
+            "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu",
             auth);
     if(!(auth & CURLAUTH_BASIC))
       /* disable username/password auth */
@@ -778,7 +780,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
       data->state.async.dns = dns;
       data->state.async.done = TRUE;
 #endif
-      infof(data, "SOCKS5: hostname '%s' found\n", hostname);
+      infof(data, "SOCKS5: hostname '%s' found", hostname);
     }
 
     if(!dns) {
@@ -820,7 +822,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
         socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i];
       }
 
-      infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", dest);
+      infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)", dest);
     }
 #ifdef ENABLE_IPV6
     else if(hp->ai_family == AF_INET6) {
@@ -834,7 +836,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
           ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i];
       }
 
-      infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", dest);
+      infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)", dest);
     }
 #endif
     else {
@@ -858,7 +860,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
       socksreq[len++] = (char) hostname_len; /* one byte address length */
       memcpy(&socksreq[len], hostname, hostname_len); /* address w/o NULL */
       len += hostname_len;
-      infof(data, "SOCKS5 connect to %s:%d (remotely resolved)\n",
+      infof(data, "SOCKS5 connect to %s:%d (remotely resolved)",
             hostname, remote_port);
     }
     /* FALLTHROUGH */
@@ -1022,7 +1024,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
     }
     sxstate(data, CONNECT_DONE);
   }
-  infof(data, "SOCKS5 request granted.\n");
+  infof(data, "SOCKS5 request granted.");
 
   *done = TRUE;
   return CURLPX_OK; /* Proxy was successful! */
index 10b942a..34bfa37 100644 (file)
@@ -328,7 +328,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   user[gss_send_token.length] = '\0';
   gss_release_name(&gss_status, &gss_client_name);
   gss_release_buffer(&gss_status, &gss_send_token);
-  infof(data, "SOCKS5 server authenticated user %s with GSS-API.\n",user);
+  infof(data, "SOCKS5 server authenticated user %s with GSS-API.",user);
   free(user);
   user = NULL;
 
@@ -344,7 +344,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   else if(gss_ret_flags & GSS_C_INTEG_FLAG)
     gss_enc = 1;
 
-  infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
+  infof(data, "SOCKS5 server supports GSS-API %s data protection.",
         (gss_enc == 0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
   /* force for the moment to no data protection */
   gss_enc = 0;
@@ -518,7 +518,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
 
   (void)curlx_nonblock(sock, TRUE);
 
-  infof(data, "SOCKS5 access with%s protection granted.\n",
+  infof(data, "SOCKS5 access with%s protection granted.",
         (socksreq[0] == 0)?"out GSS-API data":
         ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
 
index 813c6be..cb225b9 100644 (file)
@@ -327,7 +327,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     failf(data, "Failed to determine user name.");
     return CURLE_COULDNT_CONNECT;
   }
-  infof(data, "SOCKS5 server authenticated user %s with GSS-API.\n",
+  infof(data, "SOCKS5 server authenticated user %s with GSS-API.",
         names.sUserName);
   s_pSecFn->FreeContextBuffer(names.sUserName);
 
@@ -343,7 +343,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   else if(sspi_ret_flags & ISC_REQ_INTEGRITY)
     gss_enc = 1;
 
-  infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
+  infof(data, "SOCKS5 server supports GSS-API %s data protection.",
         (gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") );
   /* force to no data protection, avoid encryption/decryption for now */
   gss_enc = 0;
@@ -591,7 +591,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   }
   (void)curlx_nonblock(sock, TRUE);
 
-  infof(data, "SOCKS5 access with%s protection granted.\n",
+  infof(data, "SOCKS5 access with%s protection granted.",
         (socksreq[0] == 0)?"out GSS-API data":
         ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
 
index 9af47ea..85cf33b 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
 
 #include <curl/curl.h>
 
+#ifdef WIN32
+#include <wchar.h>
+#endif
+
 #include "strdup.h"
 #include "curl_memory.h"
 
@@ -50,6 +54,28 @@ char *curlx_strdup(const char *str)
 }
 #endif
 
+#ifdef WIN32
+/***************************************************************************
+ *
+ * Curl_wcsdup(source)
+ *
+ * Copies the 'source' wchar string to a newly allocated buffer (that is
+ * returned).
+ *
+ * Returns the new pointer or NULL on failure.
+ *
+ ***************************************************************************/
+wchar_t *Curl_wcsdup(const wchar_t *src)
+{
+  size_t length = wcslen(src);
+
+  if(length > (SIZE_T_MAX / sizeof(wchar_t)) - 1)
+    return (wchar_t *)NULL; /* integer overflow */
+
+  return (wchar_t *)Curl_memdup(src, (length + 1) * sizeof(wchar_t));
+}
+#endif
+
 /***************************************************************************
  *
  * Curl_memdup(source, length)
index 0936956..8c8a6f2 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -26,6 +26,9 @@
 #ifndef HAVE_STRDUP
 extern char *curlx_strdup(const char *str);
 #endif
+#ifdef WIN32
+wchar_t* Curl_wcsdup(const wchar_t* src);
+#endif
 void *Curl_memdup(const void *src, size_t buffer_length);
 void *Curl_saferealloc(void *ptr, size_t size);
 
index 5298a0d..8a27197 100644 (file)
@@ -188,8 +188,8 @@ curl_easy_strerror(CURLcode error)
   case CURLE_UNKNOWN_OPTION:
     return "An unknown option was passed in to libcurl";
 
-  case CURLE_TELNET_OPTION_SYNTAX :
-    return "Malformed telnet option";
+  case CURLE_SETOPT_OPTION_SYNTAX :
+    return "Malformed option provided in a setopt";
 
   case CURLE_GOT_NOTHING:
     return "Server returned nothing (no headers, no data)";
@@ -735,7 +735,7 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
 #if defined(WIN32)
   /* 'sys_nerr' is the maximum errno number, it is not widely portable */
   if(err >= 0 && err < sys_nerr)
-    strncpy(buf, strerror(err), max);
+    strncpy(buf, sys_errlist[err], max);
   else
 #endif
   {
@@ -786,6 +786,7 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
   }
 #else
   {
+    /* !checksrc! disable STRERROR 1 */
     const char *msg = strerror(err);
     if(msg)
       strncpy(buf, msg, max);
index fdd137f..a81bb81 100644 (file)
@@ -268,9 +268,9 @@ static void printoption(struct Curl_easy *data,
   if(data->set.verbose) {
     if(cmd == CURL_IAC) {
       if(CURL_TELCMD_OK(option))
-        infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
+        infof(data, "%s IAC %s", direction, CURL_TELCMD(option));
       else
-        infof(data, "%s IAC %d\n", direction, option);
+        infof(data, "%s IAC %d", direction, option);
     }
     else {
       const char *fmt = (cmd == CURL_WILL) ? "WILL" :
@@ -287,12 +287,12 @@ static void printoption(struct Curl_easy *data,
           opt = NULL;
 
         if(opt)
-          infof(data, "%s %s %s\n", direction, fmt, opt);
+          infof(data, "%s %s %s", direction, fmt, opt);
         else
-          infof(data, "%s %s %d\n", direction, fmt, option);
+          infof(data, "%s %s %d", direction, fmt, option);
       }
       else
-        infof(data, "%s %d %d\n", direction, cmd, option);
+        infof(data, "%s %d %d", direction, cmd, option);
     }
   }
 }
@@ -765,8 +765,6 @@ static void printsub(struct Curl_easy *data,
         break;
       }
     }
-    if(direction)
-      infof(data, "\n");
   }
 }
 
@@ -834,7 +832,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
           tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
         else {
           failf(data, "Syntax error in telnet option: %s", head->data);
-          result = CURLE_TELNET_OPTION_SYNTAX;
+          result = CURLE_SETOPT_OPTION_SYNTAX;
           break;
         }
         continue;
@@ -855,7 +853,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
       break;
     }
     failf(data, "Syntax error in telnet option: %s", head->data);
-    result = CURLE_TELNET_OPTION_SYNTAX;
+    result = CURLE_SETOPT_OPTION_SYNTAX;
     break;
   }
 
@@ -922,12 +920,17 @@ static void suboption(struct Curl_easy *data)
         size_t tmplen = (strlen(v->data) + 1);
         /* Add the variable only if it fits */
         if(len + tmplen < (int)sizeof(temp)-6) {
-          if(sscanf(v->data, "%127[^,],%127s", varname, varval) == 2) {
-            msnprintf((char *)&temp[len], sizeof(temp) - len,
-                      "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
-                      CURL_NEW_ENV_VALUE, varval);
-            len += tmplen;
-          }
+          int rv;
+          char sep[2] = "";
+          varval[0] = 0;
+          rv = sscanf(v->data, "%127[^,]%1[,]%127s", varname, sep, varval);
+          if(rv == 1)
+            len += msnprintf((char *)&temp[len], sizeof(temp) - len,
+                             "%c%s", CURL_NEW_ENV_VAR, varname);
+          else if(rv >= 2)
+            len += msnprintf((char *)&temp[len], sizeof(temp) - len,
+                             "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
+                             CURL_NEW_ENV_VALUE, varval);
         }
       }
       msnprintf((char *)&temp[len], sizeof(temp) - len,
index 11150af..aae997d 100644 (file)
@@ -239,7 +239,7 @@ static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
 
   infof(state->data,
         "set timeouts for state %d; Total % " CURL_FORMAT_CURL_OFF_T
-        ", retry %d maxtry %d\n",
+        ", retry %d maxtry %d",
         (int)state->state, timeout_ms, state->retry_time, state->retry_max);
 
   /* init RX time */
@@ -325,7 +325,7 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
       return CURLE_TFTP_ILLEGAL;
     }
 
-    infof(data, "got option=(%s) value=(%s)\n", option, value);
+    infof(data, "got option=(%s) value=(%s)", option, value);
 
     if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
       long blksize;
@@ -356,14 +356,14 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
       }
 
       state->blksize = (int)blksize;
-      infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
+      infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK",
             state->blksize, "requested", state->requested_blksize);
     }
     else if(checkprefix(option, TFTP_OPTION_TSIZE)) {
       long tsize = 0;
 
       tsize = strtol(value, NULL, 10);
-      infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize);
+      infof(data, "%s (%ld)", "tsize parsed from OACK", tsize);
 
       /* tsize should be ignored on upload: Who cares about the size of the
          remote file? */
@@ -397,7 +397,7 @@ static CURLcode tftp_connect_for_tx(struct tftp_state_data *state,
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   struct Curl_easy *data = state->data;
 
-  infof(data, "%s\n", "Connected for transmit");
+  infof(data, "%s", "Connected for transmit");
 #endif
   state->state = TFTP_STATE_TX;
   result = tftp_set_timeouts(state);
@@ -413,7 +413,7 @@ static CURLcode tftp_connect_for_rx(struct tftp_state_data *state,
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   struct Curl_easy *data = state->data;
 
-  infof(data, "%s\n", "Connected for receive");
+  infof(data, "%s", "Connected for receive");
 #endif
   state->state = TFTP_STATE_RX;
   result = tftp_set_timeouts(state);
@@ -596,12 +596,12 @@ static CURLcode tftp_rx(struct tftp_state_data *state,
     else if(state->block == rblock) {
       /* This is the last recently received block again. Log it and ACK it
          again. */
-      infof(data, "Received last DATA packet block %d again.\n", rblock);
+      infof(data, "Received last DATA packet block %d again.", rblock);
     }
     else {
       /* totally unexpected, just log it */
       infof(data,
-            "Received unexpected DATA packet block %d, expecting block %d\n",
+            "Received unexpected DATA packet block %d, expecting block %d",
             rblock, NEXT_BLOCKNUM(state->block));
       break;
     }
@@ -653,7 +653,7 @@ static CURLcode tftp_rx(struct tftp_state_data *state,
     /* Increment the retry count and fail if over the limit */
     state->retries++;
     infof(data,
-          "Timeout waiting for block %d ACK.  Retries = %d\n",
+          "Timeout waiting for block %d ACK.  Retries = %d",
           NEXT_BLOCKNUM(state->block), state->retries);
     if(state->retries > state->retry_max) {
       state->error = TFTP_ERR_TIMEOUT;
@@ -720,11 +720,11 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
          /* There's a bug in tftpd-hpa that causes it to send us an ack for
           * 65535 when the block number wraps to 0. So when we're expecting
           * 0, also accept 65535. See
-          * http://syslinux.zytor.com/archives/2010-September/015253.html
+          * https://www.syslinux.org/archives/2010-September/015612.html
           * */
          !(state->block == 0 && rblock == 65535)) {
         /* This isn't the expected block.  Log it and up the retry counter */
-        infof(data, "Received ACK for block %d, expecting %d\n",
+        infof(data, "Received ACK for block %d, expecting %d",
               rblock, state->block);
         state->retries++;
         /* Bail out if over the maximum */
@@ -797,7 +797,7 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
     /* Increment the retry counter and log the timeout */
     state->retries++;
     infof(data, "Timeout waiting for block %d ACK. "
-          " Retries = %d\n", NEXT_BLOCKNUM(state->block), state->retries);
+          " Retries = %d", NEXT_BLOCKNUM(state->block), state->retries);
     /* Decide if we've had enough */
     if(state->retries > state->retry_max) {
       state->error = TFTP_ERR_TIMEOUT;
@@ -906,22 +906,22 @@ static CURLcode tftp_state_machine(struct tftp_state_data *state,
 
   switch(state->state) {
   case TFTP_STATE_START:
-    DEBUGF(infof(data, "TFTP_STATE_START\n"));
+    DEBUGF(infof(data, "TFTP_STATE_START"));
     result = tftp_send_first(state, event);
     break;
   case TFTP_STATE_RX:
-    DEBUGF(infof(data, "TFTP_STATE_RX\n"));
+    DEBUGF(infof(data, "TFTP_STATE_RX"));
     result = tftp_rx(state, event);
     break;
   case TFTP_STATE_TX:
-    DEBUGF(infof(data, "TFTP_STATE_TX\n"));
+    DEBUGF(infof(data, "TFTP_STATE_TX"));
     result = tftp_tx(state, event);
     break;
   case TFTP_STATE_FIN:
-    infof(data, "%s\n", "TFTP finished");
+    infof(data, "%s", "TFTP finished");
     break;
   default:
-    DEBUGF(infof(data, "STATE: %d\n", state->state));
+    DEBUGF(infof(data, "STATE: %d", state->state));
     failf(data, "%s", "Internal state machine error");
     result = CURLE_TFTP_ILLEGAL;
     break;
@@ -1153,7 +1153,7 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data)
       size_t strn = state->rbytes - 4;
       state->error = (tftp_error_t)error;
       if(tftp_strnlen(str, strn) < strn)
-        infof(data, "TFTP error: %s\n", str);
+        infof(data, "TFTP error: %s", str);
       break;
     }
     case TFTP_EVENT_ACK:
@@ -1288,7 +1288,7 @@ static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
   result = tftp_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
   else if(!result) {
     /* The multi code doesn't have this logic for the DOING state so we
@@ -1325,7 +1325,7 @@ static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
   tftp_multi_statemach(data, dophase_done);
 
   if(*dophase_done)
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
 
   return result;
 }
index bca4e54..05fec79 100644 (file)
@@ -188,7 +188,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
     /* at this point we already verified that the callback exists
        so we compile and store the trailers buffer, then proceed */
     infof(data,
-          "Moving trailers state machine from initialized to sending.\n");
+          "Moving trailers state machine from initialized to sending.");
     data->state.trailers_state = TRAILERS_SENDING;
     Curl_dyn_init(&data->state.trailers_buf, DYN_TRAILERS);
 
@@ -211,7 +211,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
       curl_slist_free_all(trailers);
       return result;
     }
-    infof(data, "Successfully compiled trailers.\r\n");
+    infof(data, "Successfully compiled trailers.");
     curl_slist_free_all(trailers);
   }
 #endif
@@ -376,7 +376,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
       data->set.trailer_callback = NULL;
       /* mark the transfer as done */
       data->req.upload_done = TRUE;
-      infof(data, "Signaling end of chunked upload after trailers.\n");
+      infof(data, "Signaling end of chunked upload after trailers.");
     }
     else
 #endif
@@ -385,7 +385,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
         /* mark this as done once this chunk is transferred */
         data->req.upload_done = TRUE;
         infof(data,
-              "Signaling end of chunked upload via terminating chunk.\n");
+              "Signaling end of chunked upload via terminating chunk.");
       }
 
     if(added_crlf)
@@ -463,7 +463,7 @@ CURLcode Curl_readrewind(struct Curl_easy *data)
       err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
                                    data->set.ioctl_client);
       Curl_set_in_callback(data, false);
-      infof(data, "the ioctl callback returned %d\n", (int)err);
+      infof(data, "the ioctl callback returned %d", (int)err);
 
       if(err) {
         failf(data, "ioctl callback returned error %d", (int)err);
@@ -530,7 +530,7 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
   default:
     if(timeofdoc <= data->set.timevalue) {
       infof(data,
-            "The requested document is not new enough\n");
+            "The requested document is not new enough");
       data->info.timecond = TRUE;
       return FALSE;
     }
@@ -538,7 +538,7 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
   case CURL_TIMECOND_IFUNMODSINCE:
     if(timeofdoc >= data->set.timevalue) {
       infof(data,
-            "The requested document is not old enough\n");
+            "The requested document is not old enough");
       data->info.timecond = TRUE;
       return FALSE;
     }
@@ -615,7 +615,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
     else {
       /* read nothing but since we wanted nothing we consider this an OK
          situation to proceed from */
-      DEBUGF(infof(data, "readwrite_data: we're done!\n"));
+      DEBUGF(infof(data, "readwrite_data: we're done!"));
       nread = 0;
     }
 
@@ -638,10 +638,10 @@ static CURLcode readwrite_data(struct Curl_easy *data,
          server closed the connection and we bail out from this! */
 #ifdef USE_NGHTTP2
       if(is_http2 && !nread)
-        DEBUGF(infof(data, "nread == 0, stream closed, bailing\n"));
+        DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
       else
 #endif
-        DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n"));
+        DEBUGF(infof(data, "nread <= 0, server closed connection, bailing"));
       k->keepon &= ~KEEP_RECV;
       break;
     }
@@ -684,7 +684,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
           infof(data,
                 "Excess found:"
                 " excess = %zd"
-                " url = %s (zero-length body)\n",
+                " url = %s (zero-length body)",
                 nread, data->state.up.path);
         }
 
@@ -764,7 +764,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
              written to the client. */
           if(conn->chunk.datasize) {
             infof(data, "Leftovers after chunking: % "
-                  CURL_FORMAT_CURL_OFF_T "u bytes\n",
+                  CURL_FORMAT_CURL_OFF_T "u bytes",
                   conn->chunk.datasize);
           }
         }
@@ -775,7 +775,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
       /* Account for body content stored in the header buffer */
       if((k->badheader == HEADER_PARTHEADER) && !k->ignorebody) {
         size_t headlen = Curl_dyn_len(&data->state.headerb);
-        DEBUGF(infof(data, "Increasing bytecount by %zu\n", headlen));
+        DEBUGF(infof(data, "Increasing bytecount by %zu", headlen));
         k->bytecount += headlen;
       }
 
@@ -789,7 +789,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
                 " excess = %zu"
                 ", size = %" CURL_FORMAT_CURL_OFF_T
                 ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
-                ", bytecount = %" CURL_FORMAT_CURL_OFF_T "\n",
+                ", bytecount = %" CURL_FORMAT_CURL_OFF_T,
                 excess, k->size, k->maxdownload, k->bytecount);
           connclose(conn, "excess found in a read");
         }
@@ -898,7 +898,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
     /* 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. */
-    infof(data, "we are done reading and this is set to close, stop send\n");
+    infof(data, "we are done reading and this is set to close, stop send");
     k->keepon &= ~KEEP_SEND; /* no writing anymore either */
   }
 
@@ -923,7 +923,7 @@ CURLcode Curl_done_sending(struct Curl_easy *data,
   return CURLE_OK;
 }
 
-#if defined(WIN32) && !defined(USE_LWIPSOCK)
+#if defined(WIN32) && defined(USE_WINSOCK)
 #ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
 #define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
 #endif
@@ -1128,7 +1128,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
        (k->writebytecount == data->state.infilesize)) {
       /* we have sent all data we were supposed to */
       k->upload_done = TRUE;
-      infof(data, "We are completely uploaded and fine\n");
+      infof(data, "We are completely uploaded and fine");
     }
 
     if(k->upload_present != bytes_written) {
@@ -1199,7 +1199,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
 
   if(data->state.drain) {
     select_res |= CURL_CSELECT_IN;
-    DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data\n"));
+    DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data"));
   }
 
   if(!select_res) /* Call for select()/poll() only, if read/write/error
@@ -1212,8 +1212,12 @@ CURLcode Curl_readwrite(struct connectdata *conn,
   }
 
 #ifdef USE_HYPER
-  if(conn->datastream)
-    return conn->datastream(data, conn, &didwhat, done, select_res);
+  if(conn->datastream) {
+    result = conn->datastream(data, conn, &didwhat, done, select_res);
+    if(result || *done)
+      return result;
+  }
+  else {
 #endif
   /* We go ahead and do a read if we have a readable socket or if
      the stream was rewound (in which case we have data in a
@@ -1232,6 +1236,9 @@ CURLcode Curl_readwrite(struct connectdata *conn,
     if(result)
       return result;
   }
+#ifdef USE_HYPER
+  }
+#endif
 
   k->now = Curl_now();
   if(!didwhat) {
@@ -1256,7 +1263,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
         k->exp100 = EXP100_SEND_DATA;
         k->keepon |= KEEP_SEND;
         Curl_expire_done(data, EXPIRE_100_TIMEOUT);
-        infof(data, "Done waiting for 100-continue\n");
+        infof(data, "Done waiting for 100-continue");
       }
     }
   }
@@ -1496,7 +1503,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
     }
 #endif
     Curl_http2_init_state(&data->state);
-    Curl_hsts_loadcb(data, data->hsts);
+    result = Curl_hsts_loadcb(data, data->hsts);
   }
 
   /*
@@ -1632,7 +1639,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
   DEBUGASSERT(data->state.uh);
   uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl,
                     (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
-                    ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) );
+                    ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
+                    CURLU_ALLOW_SPACE);
   if(uc) {
     if(type != FOLLOW_FAKE)
       return Curl_uc_to_curlcode(uc);
@@ -1671,7 +1679,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
   data->state.url = newurl;
   data->state.url_alloc = TRUE;
 
-  infof(data, "Issue another request to this URL: '%s'\n", data->state.url);
+  infof(data, "Issue another request to this URL: '%s'", data->state.url);
 
   /*
    * We get here when the HTTP code is 300-399 (and 401). We need to perform
@@ -1714,7 +1722,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
         || data->state.httpreq == HTTPREQ_POST_FORM
         || data->state.httpreq == HTTPREQ_POST_MIME)
        && !(data->set.keep_post & CURL_REDIR_POST_301)) {
-      infof(data, "Switch from POST to GET\n");
+      infof(data, "Switch from POST to GET");
       data->state.httpreq = HTTPREQ_GET;
     }
     break;
@@ -1739,7 +1747,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
         || data->state.httpreq == HTTPREQ_POST_FORM
         || data->state.httpreq == HTTPREQ_POST_MIME)
        && !(data->set.keep_post & CURL_REDIR_POST_302)) {
-      infof(data, "Switch from POST to GET\n");
+      infof(data, "Switch from POST to GET");
       data->state.httpreq = HTTPREQ_GET;
     }
     break;
@@ -1757,7 +1765,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
         !(data->set.keep_post & CURL_REDIR_POST_303))) {
       data->state.httpreq = HTTPREQ_GET;
       data->set.upload = false;
-      infof(data, "Switch to %s\n",
+      infof(data, "Switch to %s",
             data->set.opt_no_body?"HEAD":"GET");
     }
     break;
@@ -1818,7 +1826,7 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
        to issue again, but the nghttp2 API can deliver the message to other
        streams as well, which is why this adds the check the data counters
        too. */
-    infof(data, "REFUSED_STREAM, retrying a fresh connect\n");
+    infof(data, "REFUSED_STREAM, retrying a fresh connect");
     data->state.refused_stream = FALSE; /* clear again */
     retry = TRUE;
   }
@@ -1830,8 +1838,8 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
       data->state.retrycount = 0;
       return CURLE_SEND_ERROR;
     }
-    infof(data, "Connection died, retrying a fresh connect\
-(retry count: %d)\n", data->state.retrycount);
+    infof(data, "Connection died, retrying a fresh connect (retry count: %d)",
+          data->state.retrycount);
     *url = strdup(data->state.url);
     if(!*url)
       return CURLE_OUT_OF_MEMORY;
index 1ee38af..37b6c0e 100644 (file)
 #ifdef USE_LIBIDN2
 #include <idn2.h>
 
+#if defined(WIN32) && defined(UNICODE)
+#define IDN2_LOOKUP(name, host, flags) \
+  idn2_lookup_u8((const uint8_t *)name, (uint8_t **)host, flags)
+#else
+#define IDN2_LOOKUP(name, host, flags) \
+  idn2_lookup_ul((const char *)name, (char **)host, flags)
+#endif
+
 #elif defined(USE_WIN32_IDN)
 /* prototype for curl_win32_idn_to_ascii() */
 bool curl_win32_idn_to_ascii(const char *in, char **out);
@@ -92,7 +100,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
 #include "speedcheck.h"
 #include "warnless.h"
 #include "non-ascii.h"
-#include "inet_pton.h"
 #include "getinfo.h"
 #include "urlapi-int.h"
 #include "system_win32.h"
@@ -726,7 +733,16 @@ static void conn_shutdown(struct Curl_easy *data, struct connectdata *conn)
 {
   DEBUGASSERT(conn);
   DEBUGASSERT(data);
-  infof(data, "Closing connection %ld\n", conn->connection_id);
+  infof(data, "Closing connection %ld", conn->connection_id);
+
+#ifndef USE_HYPER
+  if(conn->connect_state && conn->connect_state->prot_save) {
+    /* If this was closed with a CONNECT in progress, cleanup this temporary
+       struct arrangement */
+    data->req.p.http = NULL;
+    Curl_safefree(conn->connect_state->prot_save);
+  }
+#endif
 
   /* possible left-overs from the async name resolvers */
   Curl_resolver_cancel(data);
@@ -824,7 +840,7 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
    * are other users of it
    */
   if(CONN_INUSE(conn) && !dead_connection) {
-    DEBUGF(infof(data, "Curl_disconnect when inuse: %zu\n", CONN_INUSE(conn)));
+    DEBUGF(infof(data, "Curl_disconnect when inuse: %zu", CONN_INUSE(conn)));
     return CURLE_OK;
   }
 
@@ -957,7 +973,7 @@ static bool conn_maxage(struct Curl_easy *data,
   idletime /= 1000; /* integer seconds is fine */
 
   if(idletime > data->set.maxage_conn) {
-    infof(data, "Too old connection (%ld seconds), disconnect it\n",
+    infof(data, "Too old connection (%ld seconds), disconnect it",
           idletime);
     return TRUE;
   }
@@ -1006,7 +1022,7 @@ static bool extract_if_dead(struct connectdata *conn,
     }
 
     if(dead) {
-      infof(data, "Connection %ld seems to be dead!\n", conn->connection_id);
+      infof(data, "Connection %ld seems to be dead!", conn->connection_id);
       Curl_conncache_remove_conn(data, conn, FALSE);
       return TRUE;
     }
@@ -1122,7 +1138,7 @@ ConnectionExists(struct Curl_easy *data,
     /* Max pipe length is zero (unlimited) for multiplexed connections */
     struct Curl_llist_element *curr;
 
-    infof(data, "Found bundle for host %s: %p [%s]\n",
+    infof(data, "Found bundle for host %s: %p [%s]",
           hostbundle, (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ?
                                        "can multiplex" : "serially"));
 
@@ -1130,22 +1146,22 @@ ConnectionExists(struct Curl_easy *data,
     if(canmultiplex) {
       if(bundle->multiuse == BUNDLE_UNKNOWN) {
         if(data->set.pipewait) {
-          infof(data, "Server doesn't support multiplex yet, wait\n");
+          infof(data, "Server doesn't support multiplex yet, wait");
           *waitpipe = TRUE;
           CONNCACHE_UNLOCK(data);
           return FALSE; /* no re-use */
         }
 
-        infof(data, "Server doesn't support multiplex (yet)\n");
+        infof(data, "Server doesn't support multiplex (yet)");
         canmultiplex = FALSE;
       }
       if((bundle->multiuse == BUNDLE_MULTIPLEX) &&
          !Curl_multiplex_wanted(data->multi)) {
-        infof(data, "Could multiplex, but not asked to!\n");
+        infof(data, "Could multiplex, but not asked to!");
         canmultiplex = FALSE;
       }
       if(bundle->multiuse == BUNDLE_NO_MULTIUSE) {
-        infof(data, "Can not multiplex, even if we wanted to!\n");
+        infof(data, "Can not multiplex, even if we wanted to!");
         canmultiplex = FALSE;
       }
     }
@@ -1193,7 +1209,7 @@ ConnectionExists(struct Curl_easy *data,
              completed yet and until then we don't re-use this connection */
           if(!check->primary_ip[0]) {
             infof(data,
-                  "Connection #%ld is still name resolving, can't reuse\n",
+                  "Connection #%ld is still name resolving, can't reuse",
                   check->connection_id);
             continue;
           }
@@ -1202,7 +1218,7 @@ ConnectionExists(struct Curl_easy *data,
         if(check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) {
           foundPendingCandidate = TRUE;
           /* Don't pick a connection that hasn't connected yet */
-          infof(data, "Connection #%ld isn't open enough, can't reuse\n",
+          infof(data, "Connection #%ld isn't open enough, can't reuse",
                 check->connection_id);
           continue;
         }
@@ -1357,7 +1373,7 @@ ConnectionExists(struct Curl_easy *data,
                                         &check->ssl_config)) {
               DEBUGF(infof(data,
                            "Connection #%ld has different SSL parameters, "
-                           "can't reuse\n",
+                           "can't reuse",
                            check->connection_id));
               continue;
             }
@@ -1365,7 +1381,7 @@ ConnectionExists(struct Curl_easy *data,
               foundPendingCandidate = TRUE;
               DEBUGF(infof(data,
                            "Connection #%ld has not started SSL connect, "
-                           "can't reuse\n",
+                           "can't reuse",
                            check->connection_id));
               continue;
             }
@@ -1452,14 +1468,14 @@ ConnectionExists(struct Curl_easy *data,
             /* Multiplexed connections can only be HTTP/2 for now */
             struct http_conn *httpc = &check->proto.httpc;
             if(multiplexed >= httpc->settings.max_concurrent_streams) {
-              infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)\n",
+              infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
                     multiplexed);
               continue;
             }
             else if(multiplexed >=
                     Curl_multi_max_concurrent_streams(data->multi)) {
               infof(data, "client side MAX_CONCURRENT_STREAMS reached"
-                    ", skip (%zu)\n",
+                    ", skip (%zu)",
                     multiplexed);
               continue;
             }
@@ -1467,7 +1483,7 @@ ConnectionExists(struct Curl_easy *data,
 #endif
           /* When not multiplexed, we have a match here! */
           chosen = check;
-          infof(data, "Multiplexed connection found!\n");
+          infof(data, "Multiplexed connection found!");
           break;
         }
         else {
@@ -1490,7 +1506,7 @@ ConnectionExists(struct Curl_easy *data,
 
   if(foundPendingCandidate && data->set.pipewait) {
     infof(data,
-          "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set\n");
+          "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
     *waitpipe = TRUE;
   }
 
@@ -1505,7 +1521,7 @@ void Curl_verboseconnect(struct Curl_easy *data,
                          struct connectdata *conn)
 {
   if(data->set.verbose)
-    infof(data, "Connected to %s (%s) port %ld (#%ld)\n",
+    infof(data, "Connected to %s (%s) port %u (#%ld)",
 #ifndef CURL_DISABLE_PROXY
           conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
           conn->bits.httpproxy ? conn->http_proxy.host.dispname :
@@ -1577,12 +1593,12 @@ CURLcode Curl_idnconvert_hostname(struct Curl_easy *data,
 #else
       int flags = IDN2_NFC_INPUT;
 #endif
-      int rc = idn2_lookup_ul((const char *)host->name, &ace_hostname, flags);
+      int rc = IDN2_LOOKUP(host->name, &ace_hostname, flags);
       if(rc != IDN2_OK)
         /* fallback to TR46 Transitional mode for better IDNA2003
            compatibility */
-        rc = idn2_lookup_ul((const char *)host->name, &ace_hostname,
-                            IDN2_TRANSITIONAL);
+        rc = IDN2_LOOKUP(host->name, &ace_hostname,
+                         IDN2_TRANSITIONAL);
       if(rc == IDN2_OK) {
         host->encalloc = (char *)ace_hostname;
         /* change the name pointer to point to the encoded hostname */
@@ -1609,7 +1625,7 @@ CURLcode Curl_idnconvert_hostname(struct Curl_easy *data,
       return CURLE_URL_MALFORMAT;
     }
 #else
-    infof(data, "IDN support not present, can't parse Unicode domains\n");
+    infof(data, "IDN support not present, can't parse Unicode domains");
 #endif
   }
   return CURLE_OK;
@@ -1876,9 +1892,13 @@ static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
 #else
       scopeidx = if_nametoindex(zoneid);
 #endif
-      if(!scopeidx)
-        infof(data, "Invalid zoneid: %s; %s\n", zoneid,
-              strerror(errno));
+      if(!scopeidx) {
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+        char buffer[STRERROR_LEN];
+        infof(data, "Invalid zoneid: %s; %s", zoneid,
+              Curl_strerror(errno, buffer, sizeof(buffer)));
+#endif
+      }
       else
         conn->scope_id = scopeidx;
     }
@@ -1934,7 +1954,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
                      CURLU_DISALLOW_USER : 0) |
                     (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
     if(uc) {
-      DEBUGF(infof(data, "curl_url_set rejected %s\n", data->state.url));
+      DEBUGF(infof(data, "curl_url_set rejected %s", data->state.url));
       return Curl_uc_to_curlcode(uc);
     }
 
@@ -1979,7 +1999,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
       }
       data->state.url = url;
       data->state.url_alloc = TRUE;
-      infof(data, "Switched from HTTP to HTTPS due to HSTS => %s\n",
+      infof(data, "Switched from HTTP to HTTPS due to HSTS => %s",
             data->state.url);
     }
   }
@@ -2333,7 +2353,7 @@ static char *detect_proxy(struct Curl_easy *data,
     }
   }
   if(proxy)
-    infof(data, "Uses proxy env variable %s == '%s'\n", envp, proxy);
+    infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
 
   return proxy;
 }
@@ -2448,7 +2468,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
     conn->bits.proxy_user_passwd = TRUE; /* enable it */
   }
 
-  curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
+  (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
 
   if(portptr) {
     port = (int)strtol(portptr, NULL, 10);
@@ -2576,7 +2596,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
       no_proxy = curl_getenv(p);
     }
     if(no_proxy) {
-      infof(data, "Uses proxy env variable %s == '%s'\n", p, no_proxy);
+      infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
     }
   }
 
@@ -2871,11 +2891,13 @@ static CURLcode override_login(struct Curl_easy *data,
   char **passwdp = &conn->passwd;
   char **optionsp = &conn->options;
 
+#ifndef CURL_DISABLE_NETRC
   if(data->set.use_netrc == CURL_NETRC_REQUIRED && conn->bits.user_passwd) {
     Curl_safefree(*userp);
     Curl_safefree(*passwdp);
     conn->bits.user_passwd = FALSE; /* disable user+password */
   }
+#endif
 
   if(data->set.str[STRING_OPTIONS]) {
     free(*optionsp);
@@ -2884,6 +2906,7 @@ static CURLcode override_login(struct Curl_easy *data,
       return CURLE_OUT_OF_MEMORY;
   }
 
+#ifndef CURL_DISABLE_NETRC
   conn->bits.netrc = FALSE;
   if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
     bool netrc_user_changed = FALSE;
@@ -2895,7 +2918,7 @@ static CURLcode override_login(struct Curl_easy *data,
                           &netrc_user_changed, &netrc_passwd_changed,
                           data->set.str[STRING_NETRC_FILE]);
     if(ret > 0) {
-      infof(data, "Couldn't find host %s in the %s file; using defaults\n",
+      infof(data, "Couldn't find host %s in the %s file; using defaults",
             conn->host.name, data->set.str[STRING_NETRC_FILE]);
     }
     else if(ret < 0) {
@@ -2909,6 +2932,7 @@ static CURLcode override_login(struct Curl_easy *data,
       conn->bits.user_passwd = TRUE; /* enable user+password */
     }
   }
+#endif
 
   /* for updated strings, we update them in the URL */
   if(*userp) {
@@ -2996,6 +3020,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
   char *host_portno;
   char *portptr;
   int port = -1;
+  CURLcode result = CURLE_OK;
 
 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
   (void) data;
@@ -3025,7 +3050,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
     if(*ptr == '%') {
       /* There might be a zone identifier */
       if(strncmp("%25", ptr, 3))
-        infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
+        infof(data, "Please URL encode %% as %%25, see RFC 6874.");
       ptr++;
       /* Allow unreserved characters as defined in RFC 3986 */
       while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
@@ -3036,7 +3061,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
       /* yeps, it ended nicely with a bracket as well */
       *ptr++ = '\0';
     else
-      infof(data, "Invalid IPv6 address format\n");
+      infof(data, "Invalid IPv6 address format");
     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
@@ -3044,8 +3069,8 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
      */
 #else
     failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in!");
-    free(host_dup);
-    return CURLE_NOT_BUILT_IN;
+    result = CURLE_NOT_BUILT_IN;
+    goto error;
 #endif
   }
 
@@ -3058,10 +3083,10 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
     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",
+        failf(data, "No valid port number in connect to host string (%s)",
               host_portno);
-        hostptr = NULL;
-        port = -1;
+        result = CURLE_SETOPT_OPTION_SYNTAX;
+        goto error;
       }
       else
         port = (int)portparse; /* we know it will fit */
@@ -3072,15 +3097,16 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
   if(hostptr) {
     *hostname_result = strdup(hostptr);
     if(!*hostname_result) {
-      free(host_dup);
-      return CURLE_OUT_OF_MEMORY;
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
     }
   }
 
   *port_result = port;
 
+  error:
   free(host_dup);
-  return CURLE_OK;
+  return result;
 }
 
 /*
@@ -3176,7 +3202,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
       conn->conn_to_host.name = host;
       conn->bits.conn_to_host = TRUE;
 
-      infof(data, "Connecting to hostname: %s\n", host);
+      infof(data, "Connecting to hostname: %s", host);
     }
     else {
       /* no "connect to host" */
@@ -3187,7 +3213,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
     if(port >= 0) {
       conn->conn_to_port = port;
       conn->bits.conn_to_port = TRUE;
-      infof(data, "Connecting to port: %d\n", port);
+      infof(data, "Connecting to port: %d", port);
     }
     else {
       /* no "connect to port" */
@@ -3248,7 +3274,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
       conn->conn_to_port = as->dst.port;
       conn->bits.conn_to_port = TRUE;
       conn->bits.altused = TRUE;
-      infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d\n",
+      infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d",
             Curl_alpnid2str(srcalpnid), host, conn->remote_port,
             Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
       if(srcalpnid != as->dst.alpnid) {
@@ -3356,9 +3382,12 @@ static CURLcode resolve_server(struct Curl_easy *data,
       if(rc == CURLRESOLV_PENDING)
         *async = TRUE;
 
-      else if(rc == CURLRESOLV_TIMEDOUT)
+      else if(rc == CURLRESOLV_TIMEDOUT) {
+        failf(data, "Failed to resolve host '%s' with timeout after %ld ms",
+              connhost->dispname,
+              Curl_timediff(Curl_now(), data->progress.t_startsingle));
         result = CURLE_OPERATION_TIMEDOUT;
-
+      }
       else if(!hostaddr) {
         failf(data, "Could not resolve host: %s", connhost->dispname);
         result = CURLE_COULDNT_RESOLVE_HOST;
@@ -3600,7 +3629,7 @@ static CURLcode create_conn(struct Curl_easy *data,
   if(result)
     goto out;
 
-  /* Check for overridden login details and set them accordingly so they
+  /* Check for overridden login details and set them accordingly so that
      they are known when protocol->setup_connection is called! */
   result = override_login(data, conn);
   if(result)
@@ -3736,6 +3765,8 @@ static CURLcode create_conn(struct Curl_easy *data,
   */
   data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH];
   data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE];
+  data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
+  data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
   data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
   data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
   data->set.ssl.primary.cipher_list =
@@ -3763,8 +3794,11 @@ static CURLcode create_conn(struct Curl_easy *data,
   data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
   data->set.proxy_ssl.primary.ca_info_blob =
     data->set.blobs[BLOB_CAINFO_PROXY];
+  data->set.proxy_ssl.primary.issuercert =
+    data->set.str[STRING_SSL_ISSUERCERT_PROXY];
+  data->set.proxy_ssl.primary.issuercert_blob =
+    data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
   data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
-  data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
   data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
   data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
   data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
@@ -3773,7 +3807,6 @@ static CURLcode create_conn(struct Curl_easy *data,
   data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
 #endif
   data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE];
-  data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
   data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE];
   data->set.ssl.key = data->set.str[STRING_KEY];
   data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE];
@@ -3787,9 +3820,7 @@ static CURLcode create_conn(struct Curl_easy *data,
   data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
 #endif
 #endif
-
   data->set.ssl.key_blob = data->set.blobs[BLOB_KEY];
-  data->set.ssl.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
 
   if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary,
                                     &conn->ssl_config)) {
@@ -3841,14 +3872,14 @@ static CURLcode create_conn(struct Curl_easy *data,
     *in_connect = conn;
 
 #ifndef CURL_DISABLE_PROXY
-    infof(data, "Re-using existing connection! (#%ld) with %s %s\n",
+    infof(data, "Re-using existing connection! (#%ld) with %s %s",
           conn->connection_id,
           conn->bits.proxy?"proxy":"host",
           conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
           conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
           conn->host.dispname);
 #else
-    infof(data, "Re-using existing connection! (#%ld) with host %s\n",
+    infof(data, "Re-using existing connection! (#%ld) with host %s",
           conn->connection_id, conn->host.dispname);
 #endif
   }
@@ -3888,7 +3919,7 @@ static CURLcode create_conn(struct Curl_easy *data,
         if(conn_candidate)
           (void)Curl_disconnect(data, conn_candidate, FALSE);
         else {
-          infof(data, "No more connections allowed to host %s: %zu\n",
+          infof(data, "No more connections allowed to host %s: %zu",
                 bundlehost, max_host_connections);
           connections_available = FALSE;
         }
@@ -3908,13 +3939,13 @@ static CURLcode create_conn(struct Curl_easy *data,
       if(conn_candidate)
         (void)Curl_disconnect(data, conn_candidate, FALSE);
       else {
-        infof(data, "No connections available in cache\n");
+        infof(data, "No connections available in cache");
         connections_available = FALSE;
       }
     }
 
     if(!connections_available) {
-      infof(data, "No connections available.\n");
+      infof(data, "No connections available.");
 
       conn_free(conn);
       *in_connect = NULL;
@@ -3939,14 +3970,14 @@ static CURLcode create_conn(struct Curl_easy *data,
        connection based. */
     if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
        data->state.authhost.done) {
-      infof(data, "NTLM picked AND auth done set, clear picked!\n");
+      infof(data, "NTLM picked AND auth done set, clear picked!");
       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");
+      infof(data, "NTLM-proxy picked AND auth done set, clear picked!");
       data->state.authproxy.picked = CURLAUTH_NONE;
       data->state.authproxy.done = FALSE;
     }
index 6483208..7f03862 100644 (file)
@@ -131,7 +131,7 @@ static const char *find_host_sep(const char *url)
  */
 static bool urlchar_needs_escaping(int c)
 {
-    return !(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c));
+  return !(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c));
 }
 
 /*
@@ -580,7 +580,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname,
 }
 
 /* scan for byte values < 31 or 127 */
-static CURLUcode junkscan(const char *part)
+static bool junkscan(const char *part, unsigned int flags)
 {
   if(part) {
     static const char badbytes[]={
@@ -588,17 +588,18 @@ static CURLUcode junkscan(const char *part)
       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-      0x7f,
-      0x00 /* null-terminate */
+      0x7f, 0x00 /* null-terminate */
     };
     size_t n = strlen(part);
     size_t nfine = strcspn(part, badbytes);
     if(nfine != n)
       /* since we don't know which part is scanned, return a generic error
          code */
-      return CURLUE_MALFORMED_INPUT;
+      return TRUE;
+    if(!(flags & CURLU_ALLOW_SPACE) && strchr(part, ' '))
+      return TRUE;
   }
-  return CURLUE_OK;
+  return FALSE;
 }
 
 static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
@@ -769,8 +770,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
   size_t schemelen = 0;
   size_t urllen;
 
-  if(!url)
-    return CURLUE_MALFORMED_INPUT;
+  DEBUGASSERT(url);
 
   /*************************************************************
    * Parse the URL.
@@ -884,9 +884,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
          !(flags & CURLU_NON_SUPPORT_SCHEME))
         return CURLUE_UNSUPPORTED_SCHEME;
 
-      if(junkscan(schemep))
+      if(junkscan(schemep, flags))
         return CURLUE_MALFORMED_INPUT;
-
     }
     else {
       /* no scheme! */
@@ -927,7 +926,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
     }
   }
 
-  if(junkscan(path))
+  if(junkscan(path, flags))
     return CURLUE_MALFORMED_INPUT;
 
   if((flags & CURLU_URLENCODE) && path[0]) {
@@ -991,7 +990,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
     /*
      * Parse the login details and strip them out of the host name.
      */
-    if(junkscan(hostname))
+    if(junkscan(hostname, flags))
       return CURLUE_MALFORMED_INPUT;
 
     result = parse_hostname_login(u, &hostname, flags);
@@ -1155,7 +1154,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
       const struct Curl_handler *h =
         Curl_builtin_scheme(u->scheme);
       if(h) {
-        msnprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
+        msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
         ptr = portbuf;
       }
     }
@@ -1214,7 +1213,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
         /* there's no stored port number, but asked to deliver
            a default one for the scheme */
         if(h) {
-          msnprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
+          msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
           port = portbuf;
         }
       }
index fb905c3..6ffd976 100644 (file)
@@ -246,6 +246,7 @@ struct ssl_primary_config {
   long version_max;      /* max supported version the client wants to use*/
   char *CApath;          /* certificate dir (doesn't work on windows) */
   char *CAfile;          /* certificate to verify peer against */
+  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 */
@@ -254,6 +255,7 @@ struct ssl_primary_config {
   char *pinned_key;
   struct curl_blob *cert_blob;
   struct curl_blob *ca_info_blob;
+  struct curl_blob *issuercert_blob;
   char *curves;          /* list of curves to use */
   BIT(verifypeer);       /* set TRUE if this is desired */
   BIT(verifyhost);       /* set TRUE if CN/SAN must match hostname */
@@ -265,8 +267,6 @@ struct ssl_config_data {
   struct ssl_primary_config primary;
   long certverifyresult; /* result from the certificate verification */
   char *CRLfile;   /* CRL to check certificate revocation */
-  char *issuercert;/* optional issuer certificate filename */
-  struct curl_blob *issuercert_blob;
   curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
   void *fsslctxp;        /* parameter for call back */
   char *cert_type; /* format for certificate (default: PEM)*/
@@ -508,7 +508,9 @@ struct ConnectBits {
   BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */
   BIT(ftp_use_control_ssl); /* Enabled SSL for the control connection */
 #endif
+#ifndef CURL_DISABLE_NETRC
   BIT(netrc);         /* name+password provided by netrc */
+#endif
   BIT(bound); /* set true if bind() has already been done on this socket/
                  connection */
   BIT(multiplex); /* connection is multiplexed */
@@ -702,14 +704,15 @@ struct SingleRequest {
 #ifndef CURL_DISABLE_DOH
   struct dohdata *doh; /* DoH specific data for this request */
 #endif
-  BIT(header);       /* incoming data has HTTP header */
+  BIT(header);        /* incoming data has HTTP header */
   BIT(content_range); /* set TRUE if Content-Range: was found */
-  BIT(upload_done);  /* set to TRUE when doing chunked transfer-encoding
-                        upload and we're uploading the last chunk */
-  BIT(ignorebody);   /* we read a response-body but we ignore it! */
+  BIT(upload_done);   /* set to TRUE when doing chunked transfer-encoding
+                         upload and we're uploading the last chunk */
+  BIT(ignorebody);    /* we read a response-body but we ignore it! */
   BIT(http_bodyless); /* HTTP response status code is between 100 and 199,
                          204 or 304 */
-  BIT(chunk); /* if set, this is a chunked transfer-encoding */
+  BIT(chunk);         /* if set, this is a chunked transfer-encoding */
+  BIT(ignore_cl);     /* ignore content-length */
   BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding
                          on upload */
   BIT(getheader);    /* TRUE if header parsing is wanted */
@@ -1411,6 +1414,7 @@ struct UrlState {
   trailers_state trailers_state; /* whether we are sending trailers
                                        and what stage are we at */
 #ifdef USE_HYPER
+  bool hconnect;  /* set if a CONNECT request */
   CURLcode hresult; /* used to pass return codes back from hyper callbacks */
 #endif
 
@@ -1726,8 +1730,10 @@ struct UserDefined {
                                */
   curl_sshkeycallback ssh_keyfunc; /* key matching callback */
   void *ssh_keyfunc_userp;         /* custom pointer to callback */
+#ifndef CURL_DISABLE_NETRC
   enum CURL_NETRC_OPTION
        use_netrc;        /* defined in include/curl.h */
+#endif
   curl_usessl use_ssl;   /* if AUTH TLS is to be attempted etc, for FTP or
                             IMAP or POP3 or others! */
   long new_file_perms;    /* Permissions to use when creating remote files */
@@ -1847,9 +1853,9 @@ struct UserDefined {
   BIT(disallow_username_in_url); /* disallow username in url */
   BIT(doh); /* DNS-over-HTTPS enabled */
   BIT(doh_get); /* use GET for DoH requests, instead of POST */
-  BIT(doh_verifypeer);     /* DOH certificate peer verification */
-  BIT(doh_verifyhost);     /* DOH certificate hostname verification */
-  BIT(doh_verifystatus);   /* DOH certificate status verification */
+  BIT(doh_verifypeer);     /* DoH certificate peer verification */
+  BIT(doh_verifyhost);     /* DoH certificate hostname verification */
+  BIT(doh_verifystatus);   /* DoH certificate status verification */
   BIT(http09_allowed); /* allow HTTP/0.9 responses */
   BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some
                                 recipients */
index 2602ffd..94f8f8c 100644 (file)
@@ -112,7 +112,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
 
   /* Ensure we have a valid challenge message */
   if(!Curl_bufref_len(chlg)) {
-    infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n");
+    infof(data, "DIGEST-MD5 handshake failure (empty challenge message)");
     return CURLE_BAD_CONTENT_ENCODING;
   }
 
@@ -197,7 +197,9 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
      status == SEC_I_COMPLETE_AND_CONTINUE)
     s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
   else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
     char buffer[STRERROR_LEN];
+#endif
 
     s_pSecFn->FreeCredentialsHandle(&credentials);
     Curl_sspi_free_identity(p_identity);
@@ -207,7 +209,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
     if(status == SEC_E_INSUFFICIENT_MEMORY)
       return CURLE_OUT_OF_MEMORY;
 
-    infof(data, "schannel: InitializeSecurityContext failed: %s\n",
+    infof(data, "schannel: InitializeSecurityContext failed: %s",
           Curl_sspi_strerror(status, buffer, sizeof(buffer)));
 
     return CURLE_AUTH_ERROR;
@@ -461,7 +463,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
     if(status == SEC_E_OK)
       output_token_len = chlg_buf[4].cbBuffer;
     else { /* delete the context so a new one can be made */
-      infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx\n",
+      infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx",
             (long)status);
       s_pSecFn->DeleteSecurityContext(digest->http_context);
       Curl_safefree(digest->http_context);
@@ -585,7 +587,9 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
        status == SEC_I_COMPLETE_AND_CONTINUE)
       s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
     else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
       char buffer[STRERROR_LEN];
+#endif
 
       s_pSecFn->FreeCredentialsHandle(&credentials);
 
@@ -597,7 +601,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
       if(status == SEC_E_INSUFFICIENT_MEMORY)
         return CURLE_OUT_OF_MEMORY;
 
-      infof(data, "schannel: InitializeSecurityContext failed: %s\n",
+      infof(data, "schannel: InitializeSecurityContext failed: %s",
             Curl_sspi_strerror(status, buffer, sizeof(buffer)));
 
       return CURLE_AUTH_ERROR;
index b43982b..67d43bd 100644 (file)
@@ -123,7 +123,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
 
   if(chlg) {
     if(!Curl_bufref_len(chlg)) {
-      infof(data, "GSSAPI handshake failure (empty challenge message)\n");
+      infof(data, "GSSAPI handshake failure (empty challenge message)");
       return CURLE_BAD_CONTENT_ENCODING;
     }
     input_token.value = (void *) Curl_bufref_ptr(chlg);
@@ -170,6 +170,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
  * Parameters:
  *
  * data    [in]     - The session handle.
+ * authzid [in]     - The authorization identity if some.
  * chlg    [in]     - Optional challenge message.
  * krb5    [in/out] - The Kerberos 5 data struct being used and modified.
  * out     [out]    - The result storage.
@@ -177,6 +178,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
  * Returns CURLE_OK on success.
  */
 CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
+                                                  const char *authzid,
                                                   const struct bufref *chlg,
                                                   struct kerberos5data *krb5,
                                                   struct bufref *out)
@@ -189,39 +191,17 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
   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;
-  unsigned int outdata = 0;
+  unsigned char *indata;
   gss_qop_t qop = GSS_C_QOP_DEFAULT;
   unsigned int sec_layer = 0;
   unsigned int max_size = 0;
-  gss_name_t username = GSS_C_NO_NAME;
-  gss_buffer_desc username_token;
 
   /* Ensure we have a valid challenge message */
   if(!Curl_bufref_len(chlg)) {
-    infof(data, "GSSAPI handshake failure (empty security message)\n");
+    infof(data, "GSSAPI handshake failure (empty security message)");
     return CURLE_BAD_CONTENT_ENCODING;
   }
 
-  /* Get the fully qualified username back from the context */
-  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);
-    return CURLE_AUTH_ERROR;
-  }
-
-  /* Convert the username from internal format to a displayable token */
-  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);
-    return CURLE_AUTH_ERROR;
-  }
-
   /* Setup the challenge "input" security buffer */
   input_token.value = (void *) Curl_bufref_ptr(chlg);
   input_token.length = Curl_bufref_len(chlg);
@@ -232,32 +212,32 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
   if(GSS_ERROR(major_status)) {
     Curl_gss_log_error(data, "gss_unwrap() failed: ",
                        major_status, minor_status);
-    gss_release_buffer(&unused_status, &username_token);
     return CURLE_BAD_CONTENT_ENCODING;
   }
 
   /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
   if(output_token.length != 4) {
-    infof(data, "GSSAPI handshake failure (invalid security data)\n");
-    gss_release_buffer(&unused_status, &username_token);
+    infof(data, "GSSAPI handshake failure (invalid security data)");
     return CURLE_BAD_CONTENT_ENCODING;
   }
 
-  /* Copy the data out and free the challenge as it is not required anymore */
-  memcpy(&indata, output_token.value, 4);
+  /* Extract the security layer and the maximum message size */
+  indata = output_token.value;
+  sec_layer = indata[0];
+  max_size = (indata[1] << 16) | (indata[2] << 8) | indata[3];
+
+  /* Free the challenge as it is not required anymore */
   gss_release_buffer(&unused_status, &output_token);
 
-  /* Extract the security layer */
-  sec_layer = indata & 0x000000FF;
+  /* Process the security layer */
   if(!(sec_layer & GSSAUTH_P_NONE)) {
-    infof(data, "GSSAPI handshake failure (invalid security layer)\n");
+    infof(data, "GSSAPI handshake failure (invalid security layer)");
 
-    gss_release_buffer(&unused_status, &username_token);
     return CURLE_BAD_CONTENT_ENCODING;
   }
+  sec_layer &= GSSAUTH_P_NONE;  /* We do not support a security layer */
 
-  /* Extract the maximum message size the server can receive */
-  max_size = ntohl(indata & 0xFFFFFF00);
+  /* Process the maximum message size the server can receive */
   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
@@ -266,26 +246,24 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
   }
 
   /* Allocate our message */
-  messagelen = sizeof(outdata) + username_token.length + 1;
+  messagelen = 4;
+  if(authzid)
+    messagelen += strlen(authzid);
   message = malloc(messagelen);
-  if(!message) {
-    gss_release_buffer(&unused_status, &username_token);
+  if(!message)
     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));
-  memcpy(message + sizeof(outdata), username_token.value,
-         username_token.length);
-  message[messagelen - 1] = '\0';
-
-  /* Free the username token as it is not required anymore */
-  gss_release_buffer(&unused_status, &username_token);
+  /* Populate the message with the security layer and client supported receive
+     message size. */
+  message[0] = sec_layer & 0xFF;
+  message[1] = (max_size >> 16) & 0xFF;
+  message[2] = (max_size >> 8) & 0xFF;
+  message[3] = max_size & 0xFF;
+
+  /* If given, append the authorization identity. */
+
+  if(authzid && *authzid)
+    memcpy(message + 4, authzid, messagelen - 4);
 
   /* Setup the "authentication data" security buffer */
   input_token.value = message;
index e110644..c652fd7 100644 (file)
@@ -173,7 +173,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
 
   if(chlg) {
     if(!Curl_bufref_len(chlg)) {
-      infof(data, "GSSAPI handshake failure (empty challenge message)\n");
+      infof(data, "GSSAPI handshake failure (empty challenge message)");
       return CURLE_BAD_CONTENT_ENCODING;
     }
 
@@ -238,13 +238,15 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
  * Parameters:
  *
  * data    [in]     - The session handle.
- * chlg     [in]     - The optional challenge message.
+ * authzid [in]     - The authorization identity if some.
+ * chlg    [in]     - The optional challenge message.
  * krb5    [in/out] - The Kerberos 5 data struct being used and modified.
  * out     [out]    - The result storage.
  *
  * Returns CURLE_OK on success.
  */
 CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
+                                                  const char *authzid,
                                                   const struct bufref *chlg,
                                                   struct kerberos5data *krb5,
                                                   struct bufref *out)
@@ -260,19 +262,20 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
   SecBuffer wrap_buf[3];
   SecBufferDesc input_desc;
   SecBufferDesc wrap_desc;
-  unsigned long indata = 0;
-  unsigned long outdata = 0;
+  unsigned char *indata;
   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;
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) data;
+#endif
 
   /* Ensure we have a valid challenge message */
   if(!Curl_bufref_len(chlg)) {
-    infof(data, "GSSAPI handshake failure (empty security message)\n");
+    infof(data, "GSSAPI handshake failure (empty security message)");
     return CURLE_BAD_CONTENT_ENCODING;
   }
 
@@ -287,17 +290,6 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
   if(status != SEC_E_OK)
     return CURLE_AUTH_ERROR;
 
-  /* Get the fully qualified username back from the context */
-  status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials,
-                                                SECPKG_CRED_ATTR_NAMES,
-                                                &names);
-
-  if(status == SEC_E_INSUFFICIENT_MEMORY)
-    return CURLE_OUT_OF_MEMORY;
-
-  if(status != SEC_E_OK)
-    return CURLE_AUTH_ERROR;
-
   /* Setup the "input" security buffer */
   input_desc.ulVersion = SECBUFFER_VERSION;
   input_desc.cBuffers = 2;
@@ -312,29 +304,32 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
   /* 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");
+    infof(data, "GSSAPI handshake failure (empty security message)");
     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");
+    infof(data, "GSSAPI handshake failure (invalid security data)");
     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);
+  /* Extract the security layer and the maximum message size */
+  indata = input_buf[1].pvBuffer;
+  sec_layer = indata[0];
+  max_size = (indata[1] << 16) | (indata[2] << 8) | indata[3];
+
+  /* Free the challenge as it is not required anymore */
   s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer);
 
-  /* Extract the security layer */
-  sec_layer = indata & 0x000000FF;
+  /* Process the security layer */
   if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) {
-    infof(data, "GSSAPI handshake failure (invalid security layer)\n");
+    infof(data, "GSSAPI handshake failure (invalid security layer)");
     return CURLE_BAD_CONTENT_ENCODING;
   }
+  sec_layer &= KERB_WRAP_NO_ENCRYPT;  /* We do not support a security layer */
 
-  /* Extract the maximum message size the server can receive */
-  max_size = ntohl(indata & 0xFFFFFF00);
+  /* Process the maximum message size the server can receive */
   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
@@ -347,33 +342,28 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
   if(!trailer)
     return CURLE_OUT_OF_MEMORY;
 
-  /* Convert the user name to UTF8 when operating with Unicode */
-  user_name = curlx_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;
+  messagelen = 4;
+  if(authzid)
+    messagelen += strlen(authzid);
   message = malloc(messagelen);
   if(!message) {
     free(trailer);
-    curlx_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);
-  curlx_unicodefree(user_name);
+  /* Populate the message with the security layer and client supported receive
+     message size. */
+  message[0] = sec_layer & 0xFF;
+  message[1] = (max_size >> 16) & 0xFF;
+  message[2] = (max_size >> 8) & 0xFF;
+  message[3] = max_size & 0xFF;
+
+  /* If given, append the authorization identity. */
+
+  if(authzid && *authzid)
+    memcpy(message + 4, authzid, messagelen - 4);
 
   /* Allocate the padding */
   padding = malloc(sizes.cbBlockSize);
index 47e5357..0aa3f1c 100644 (file)
@@ -182,7 +182,7 @@ static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
          (target_info_offset + target_info_len) > type2len ||
          target_info_offset < 48) {
         infof(data, "NTLM handshake failure (bad type-2 message). "
-              "Target Info Offset Len is set incorrect by the peer\n");
+              "Target Info Offset Len is set incorrect by the peer");
         return CURLE_BAD_CONTENT_ENCODING;
       }
 
@@ -286,7 +286,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
      (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) ||
      (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) {
     /* This was not a good enough type-2 message */
-    infof(data, "NTLM handshake failure (bad type-2 message)\n");
+    infof(data, "NTLM handshake failure (bad type-2 message)");
     return CURLE_BAD_CONTENT_ENCODING;
   }
 
@@ -296,7 +296,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
   if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) {
     result = ntlm_decode_type2_target(data, type2ref, ntlm);
     if(result) {
-      infof(data, "NTLM handshake failure (bad type-2 message)\n");
+      infof(data, "NTLM handshake failure (bad type-2 message)");
       return result;
     }
   }
@@ -533,7 +533,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
   /* Get the machine's un-qualified host name as NTLM doesn't like the fully
      qualified domain name */
   if(Curl_gethostname(host, sizeof(host))) {
-    infof(data, "gethostname() failed, continuing without!\n");
+    infof(data, "gethostname() failed, continuing without!");
     hostlen = 0;
   }
   else {
index 1b1a176..3e39dad 100644 (file)
@@ -206,7 +206,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
 
   /* Ensure we have a valid type-2 message */
   if(!Curl_bufref_len(type2)) {
-    infof(data, "NTLM handshake failure (empty type-2 message)\n");
+    infof(data, "NTLM handshake failure (empty type-2 message)");
     return CURLE_BAD_CONTENT_ENCODING;
   }
 
@@ -253,6 +253,9 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
   unsigned long attrs;
   TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
 
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) data;
+#endif
   (void) passwdp;
   (void) userp;
 
@@ -309,7 +312,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
                                                &type_3_desc,
                                                &attrs, &expiry);
   if(status != SEC_E_OK) {
-    infof(data, "NTLM handshake failure (type-3 message): Status=%x\n",
+    infof(data, "NTLM handshake failure (type-3 message): Status=%x",
           status);
 
     if(status == SEC_E_INSUFFICIENT_MEMORY)
index 120925f..8e8932b 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -137,8 +137,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
 
     /* Ensure we have a valid challenge message */
     if(!chlg) {
-      infof(data, "SPNEGO handshake failure (empty challenge message)\n");
-
+      infof(data, "SPNEGO handshake failure (empty challenge message)");
       return CURLE_BAD_CONTENT_ENCODING;
     }
 
index 4aa1ba9..68bb17d 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -191,8 +191,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
 
     /* Ensure we have a valid challenge message */
     if(!chlg) {
-      infof(data, "SPNEGO handshake failure (empty challenge message)\n");
-
+      infof(data, "SPNEGO handshake failure (empty challenge message)");
       return CURLE_BAD_CONTENT_ENCODING;
     }
 
index ec5b000..47a7c0b 100644 (file)
@@ -194,6 +194,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
 /* 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 *authzid,
                                                   const struct bufref *chlg,
                                                   struct kerberos5data *krb5,
                                                   struct bufref *out);
index b67b9a4..c84ef85 100644 (file)
 #endif
 
 #ifdef HAVE_BROTLI
-static size_t brotli_version(char *buf, size_t bufsz)
+static void brotli_version(char *buf, size_t bufsz)
 {
   uint32_t brotli_version = BrotliDecoderVersion();
   unsigned int major = brotli_version >> 24;
   unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12;
   unsigned int patch = brotli_version & 0x00000FFF;
-
-  return msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
+  (void)msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
 }
 #endif
 
 #ifdef HAVE_ZSTD
-static size_t zstd_version(char *buf, size_t bufsz)
+static void zstd_version(char *buf, size_t bufsz)
 {
   unsigned long zstd_version = (unsigned long)ZSTD_versionNumber();
   unsigned int major = (unsigned int)(zstd_version / (100 * 100));
   unsigned int minor = (unsigned int)((zstd_version -
-                         (major * 100 * 100)) / 100);
+                                       (major * 100 * 100)) / 100);
   unsigned int patch = (unsigned int)(zstd_version -
-                         (major * 100 * 100) - (minor * 100));
-
-  return msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
+                                      (major * 100 * 100) - (minor * 100));
+  (void)msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
 }
 #endif
 
index 7f07675..9fcfe81 100644 (file)
@@ -28,6 +28,9 @@
 #include <nghttp3/nghttp3.h>
 #ifdef USE_OPENSSL
 #include <openssl/err.h>
+#include <ngtcp2/ngtcp2_crypto_openssl.h>
+#elif defined(USE_GNUTLS)
+#include <ngtcp2/ngtcp2_crypto_gnutls.h>
 #endif
 #include "urldata.h"
 #include "sendf.h"
@@ -86,7 +89,8 @@ struct h3out {
 #define QUIC_PRIORITY \
   "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
   "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
-  "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1"
+  "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
+  "%DISABLE_TLS13_COMPAT_MODE"
 #endif
 
 static CURLcode ng_process_ingress(struct Curl_easy *data,
@@ -116,42 +120,6 @@ static void quic_printf(void *user_data, const char *fmt, ...)
 }
 #endif
 
-#ifdef USE_OPENSSL
-static ngtcp2_crypto_level
-quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level)
-{
-  switch(ossl_level) {
-  case ssl_encryption_initial:
-    return NGTCP2_CRYPTO_LEVEL_INITIAL;
-  case ssl_encryption_early_data:
-    return NGTCP2_CRYPTO_LEVEL_EARLY;
-  case ssl_encryption_handshake:
-    return NGTCP2_CRYPTO_LEVEL_HANDSHAKE;
-  case ssl_encryption_application:
-    return NGTCP2_CRYPTO_LEVEL_APPLICATION;
-  default:
-    assert(0);
-  }
-}
-#elif defined(USE_GNUTLS)
-static ngtcp2_crypto_level
-quic_from_gtls_level(gnutls_record_encryption_level_t gtls_level)
-{
-  switch(gtls_level) {
-  case GNUTLS_ENCRYPTION_LEVEL_INITIAL:
-    return NGTCP2_CRYPTO_LEVEL_INITIAL;
-  case GNUTLS_ENCRYPTION_LEVEL_EARLY:
-    return NGTCP2_CRYPTO_LEVEL_EARLY;
-  case GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE:
-    return NGTCP2_CRYPTO_LEVEL_HANDSHAKE;
-  case GNUTLS_ENCRYPTION_LEVEL_APPLICATION:
-    return NGTCP2_CRYPTO_LEVEL_APPLICATION;
-  default:
-    assert(0);
-  }
-}
-#endif
-
 static void qlog_callback(void *user_data, uint32_t flags,
                           const void *data, size_t datalen)
 {
@@ -222,27 +190,9 @@ static int write_client_handshake(struct quicsocket *qs,
                                   ngtcp2_crypto_level level,
                                   const uint8_t *data, size_t len)
 {
-  struct quic_handshake *crypto_data;
   int rv;
 
-  crypto_data = &qs->crypto_data[level];
-  if(!crypto_data->buf) {
-    crypto_data->buf = malloc(4096);
-    if(!crypto_data->buf)
-      return 0;
-    crypto_data->alloclen = 4096;
-  }
-
-  /* TODO Just pretend that handshake does not grow more than 4KiB for
-     now */
-  assert(crypto_data->len + len <= crypto_data->alloclen);
-
-  memcpy(&crypto_data->buf[crypto_data->len], data, len);
-  crypto_data->len += len;
-
-  rv = ngtcp2_conn_submit_crypto_data(
-    qs->qconn, level, (uint8_t *)(&crypto_data->buf[crypto_data->len] - len),
-    len);
+  rv = ngtcp2_conn_submit_crypto_data(qs->qconn, level, data, len);
   if(rv) {
     H3BUGF(fprintf(stderr, "write_client_handshake failed\n"));
   }
@@ -259,7 +209,7 @@ static int quic_set_encryption_secrets(SSL *ssl,
                                        size_t secretlen)
 {
   struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
-  int level = quic_from_ossl_level(ossl_level);
+  int level = ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level);
 
   if(ngtcp2_crypto_derive_and_install_rx_key(
        qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
@@ -281,7 +231,8 @@ static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
                                    const uint8_t *data, size_t len)
 {
   struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
-  ngtcp2_crypto_level level = quic_from_ossl_level(ossl_level);
+  ngtcp2_crypto_level level =
+      ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level);
 
   return write_client_handshake(qs, level, data, len);
 }
@@ -369,7 +320,8 @@ static int secret_func(gnutls_session_t ssl,
                        const void *tx_secret, size_t secretlen)
 {
   struct quicsocket *qs = gnutls_session_get_ptr(ssl);
-  int level = quic_from_gtls_level(gtls_level);
+  int level =
+      ngtcp2_crypto_gnutls_from_gnutls_record_encryption_level(gtls_level);
 
   if(level != NGTCP2_CRYPTO_LEVEL_EARLY &&
      ngtcp2_crypto_derive_and_install_rx_key(
@@ -394,7 +346,8 @@ static int read_func(gnutls_session_t ssl,
                      size_t len)
 {
   struct quicsocket *qs = gnutls_session_get_ptr(ssl);
-  ngtcp2_crypto_level level = quic_from_gtls_level(gtls_level);
+  ngtcp2_crypto_level level =
+      ngtcp2_crypto_gnutls_from_gnutls_record_encryption_level(gtls_level);
   int rv;
 
   if(htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
@@ -542,22 +495,6 @@ static int quic_init_ssl(struct quicsocket *qs)
 }
 #endif
 
-static int
-cb_recv_crypto_data(ngtcp2_conn *tconn, ngtcp2_crypto_level crypto_level,
-                    uint64_t offset,
-                    const uint8_t *data, size_t datalen,
-                    void *user_data)
-{
-  (void)offset;
-  (void)user_data;
-
-  if(ngtcp2_crypto_read_write_crypto_data(tconn, crypto_level, data,
-                                          datalen) != 0)
-    return NGTCP2_ERR_CRYPTO;
-
-  return 0;
-}
-
 static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
 {
   (void)user_data;
@@ -622,8 +559,8 @@ cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
   return 0;
 }
 
-static int cb_stream_close(ngtcp2_conn *tconn, int64_t stream_id,
-                           uint64_t app_error_code,
+static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags,
+                           int64_t stream_id, uint64_t app_error_code,
                            void *user_data, void *stream_user_data)
 {
   struct quicsocket *qs = (struct quicsocket *)user_data;
@@ -632,6 +569,10 @@ static int cb_stream_close(ngtcp2_conn *tconn, int64_t stream_id,
   (void)stream_user_data;
   /* stream is closed... */
 
+  if(!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
+    app_error_code = NGHTTP3_H3_NO_ERROR;
+  }
+
   rv = nghttp3_conn_close_stream(qs->h3conn, stream_id,
                                  app_error_code);
   if(rv) {
@@ -652,7 +593,25 @@ static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
   (void)app_error_code;
   (void)stream_user_data;
 
-  rv = nghttp3_conn_reset_stream(qs->h3conn, stream_id);
+  rv = nghttp3_conn_shutdown_stream_read(qs->h3conn, stream_id);
+  if(rv) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+
+static int cb_stream_stop_sending(ngtcp2_conn *tconn, int64_t stream_id,
+                                  uint64_t app_error_code, void *user_data,
+                                  void *stream_user_data)
+{
+  struct quicsocket *qs = (struct quicsocket *)user_data;
+  int rv;
+  (void)tconn;
+  (void)app_error_code;
+  (void)stream_user_data;
+
+  rv = nghttp3_conn_shutdown_stream_read(qs->h3conn, stream_id);
   if(rv) {
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
@@ -712,14 +671,13 @@ static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
 static ngtcp2_callbacks ng_callbacks = {
   ngtcp2_crypto_client_initial_cb,
   NULL, /* recv_client_initial */
-  cb_recv_crypto_data,
+  ngtcp2_crypto_recv_crypto_data_cb,
   cb_handshake_completed,
   NULL, /* recv_version_negotiation */
   ngtcp2_crypto_encrypt_cb,
   ngtcp2_crypto_decrypt_cb,
   ngtcp2_crypto_hp_mask_cb,
   cb_recv_stream_data,
-  NULL, /* acked_crypto_offset */
   cb_acked_stream_data_offset,
   NULL, /* stream_open */
   cb_stream_close,
@@ -744,7 +702,9 @@ static ngtcp2_callbacks ng_callbacks = {
   ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
   NULL, /* recv_datagram */
   NULL, /* ack_datagram */
-  NULL  /* lost_datagram */
+  NULL, /* lost_datagram */
+  NULL, /* get_path_challenge_data */
+  cb_stream_stop_sending
 };
 
 /*
@@ -778,7 +738,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
 
-  infof(data, "Connect socket %d over QUIC to %s:%d\n",
+  infof(data, "Connect socket %d over QUIC to %s:%d",
         sockfd, ipbuf, port);
 
   qs->version = NGTCP2_PROTO_VER_MAX;
@@ -827,15 +787,14 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
 }
 
 /*
- * Store ngtp2 version info in this buffer, Prefix with a space.  Return total
- * length written.
+ * Store ngtcp2 version info in this buffer.
  */
-int Curl_quic_ver(char *p, size_t len)
+void Curl_quic_ver(char *p, size_t len)
 {
   const ngtcp2_info *ng2 = ngtcp2_version(0);
   nghttp3_info *ht3 = nghttp3_version(0);
-  return msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
-                   ng2->version_str, ht3->version_str);
+  (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
+                  ng2->version_str, ht3->version_str);
 }
 
 static int ng_getsock(struct Curl_easy *data, struct connectdata *conn,
@@ -859,7 +818,6 @@ static int ng_getsock(struct Curl_easy *data, struct connectdata *conn,
 
 static void qs_disconnect(struct quicsocket *qs)
 {
-  int i;
   if(!qs->conn) /* already closed */
     return;
   qs->conn = NULL;
@@ -880,8 +838,6 @@ static void qs_disconnect(struct quicsocket *qs)
     qs->cred = NULL;
   }
 #endif
-  for(i = 0; i < 3; i++)
-    Curl_safefree(qs->crypto_data[i].buf);
   nghttp3_conn_del(qs->h3conn);
   ngtcp2_conn_del(qs->qconn);
 #ifdef USE_OPENSSL
@@ -951,7 +907,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
   (void)stream_id;
   (void)app_error_code;
   (void)user_data;
-  H3BUGF(infof(data, "cb_h3_stream_close CALLED\n"));
+  H3BUGF(infof(data, "cb_h3_stream_close CALLED"));
 
   stream->closed = TRUE;
   Curl_expire(data, 0, EXPIRE_QUIC);
@@ -1143,14 +1099,10 @@ static nghttp3_callbacks ngh3_callbacks = {
   NULL, /* begin_trailers */
   cb_h3_recv_header,
   NULL, /* end_trailers */
-  NULL, /* http_begin_push_promise */
-  NULL, /* http_recv_push_promise */
-  NULL, /* http_end_push_promise */
-  NULL, /* http_cancel_push */
   cb_h3_send_stop_sending,
-  NULL, /* push_stream */
   NULL, /* end_stream */
   NULL, /* reset_stream */
+  NULL /* shutdown */
 };
 
 static int init_ngh3_conn(struct quicsocket *qs)
@@ -1287,7 +1239,7 @@ static ssize_t ngh3_stream_recv(struct Curl_easy *data,
     return 0;
   }
 
-  infof(data, "ngh3_stream_recv returns 0 bytes and EAGAIN\n");
+  infof(data, "ngh3_stream_recv returns 0 bytes and EAGAIN");
   *curlcode = CURLE_AGAIN;
   return -1;
 }
@@ -1304,7 +1256,7 @@ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
   if(!data->set.postfields) {
     stream->h3out->used -= datalen;
     H3BUGF(infof(data,
-                 "cb_h3_acked_stream_data, %zd bytes, %zd left unacked\n",
+                 "cb_h3_acked_stream_data, %zd bytes, %zd left unacked",
                  datalen, stream->h3out->used));
     DEBUGASSERT(stream->h3out->used < H3_SEND_SIZE);
 
@@ -1366,13 +1318,13 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
       if(!stream->upload_left)
         *pflags = NGHTTP3_DATA_FLAG_EOF;
     }
-    H3BUGF(infof(data, "cb_h3_readfunction %zd bytes%s (at %zd unacked)\n",
+    H3BUGF(infof(data, "cb_h3_readfunction %zd bytes%s (at %zd unacked)",
                  nread, *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
                  out->used));
   }
   if(stream->upload_done && !stream->upload_len &&
      (stream->upload_left <= 0)) {
-    H3BUGF(infof(data, "!!!!!!!!! cb_h3_readfunction sets EOF\n"));
+    H3BUGF(infof(data, "!!!!!!!!! cb_h3_readfunction sets EOF"));
     *pflags = NGHTTP3_DATA_FLAG_EOF;
     return nread ? 1 : 0;
   }
@@ -1565,7 +1517,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
     if(acc > MAX_ACC) {
       infof(data, "http_request: Warning: The cumulative length of all "
             "headers exceeds %d bytes and that could cause the "
-            "stream to be rejected.\n", MAX_ACC);
+            "stream to be rejected.", MAX_ACC);
     }
   }
 
@@ -1611,7 +1563,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
 
   Curl_safefree(nva);
 
-  infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)\n",
+  infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)",
         stream3_id, (void *)data);
 
   return CURLE_OK;
@@ -1641,7 +1593,7 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data,
     sent = len;
   }
   else {
-    H3BUGF(infof(data, "ngh3_stream_send() wants to send %zd bytes\n",
+    H3BUGF(infof(data, "ngh3_stream_send() wants to send %zd bytes",
                  len));
     if(!stream->upload_len) {
       stream->upload_mem = mem;
@@ -1660,6 +1612,12 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data,
     return -1;
   }
 
+  /* Reset post upload buffer after resumed. */
+  if(stream->upload_mem) {
+    stream->upload_mem = NULL;
+    stream->upload_len = 0;
+  }
+
   *curlcode = CURLE_OK;
   return sent;
 }
@@ -1758,8 +1716,7 @@ static CURLcode ng_flush_egress(struct Curl_easy *data,
   int rv;
   ssize_t sent;
   ssize_t outlen;
-  uint8_t out[NGTCP2_MAX_PKTLEN_IPV4];
-  size_t pktlen;
+  uint8_t out[NGTCP2_MAX_UDP_PAYLOAD_SIZE];
   ngtcp2_path_storage ps;
   ngtcp2_tstamp ts = timestamp();
   struct sockaddr_storage remote_addr;
@@ -1772,19 +1729,6 @@ static CURLcode ng_flush_egress(struct Curl_easy *data,
   ssize_t ndatalen;
   uint32_t flags;
 
-  switch(qs->local_addr.ss_family) {
-  case AF_INET:
-    pktlen = NGTCP2_MAX_PKTLEN_IPV4;
-    break;
-#ifdef ENABLE_IPV6
-  case AF_INET6:
-    pktlen = NGTCP2_MAX_PKTLEN_IPV6;
-    break;
-#endif
-  default:
-    assert(0);
-  }
-
   rv = ngtcp2_conn_handle_expiry(qs->qconn, ts);
   if(rv) {
     failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
@@ -1811,15 +1755,16 @@ static CURLcode ng_flush_egress(struct Curl_easy *data,
 
     flags = NGTCP2_WRITE_STREAM_FLAG_MORE |
             (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0);
-    outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, NULL, out, pktlen,
+    outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, NULL, out,
+                                       sizeof(out),
                                        &ndatalen, flags, stream_id,
                                        (const ngtcp2_vec *)vec, veccnt, ts);
     if(outlen == 0) {
       break;
     }
     if(outlen < 0) {
-      if(outlen == NGTCP2_ERR_STREAM_DATA_BLOCKED ||
-         outlen == NGTCP2_ERR_STREAM_SHUT_WR) {
+      switch(outlen) {
+      case NGTCP2_ERR_STREAM_DATA_BLOCKED:
         assert(ndatalen == -1);
         rv = nghttp3_conn_block_stream(qs->h3conn, stream_id);
         if(rv) {
@@ -1828,8 +1773,17 @@ static CURLcode ng_flush_egress(struct Curl_easy *data,
           return CURLE_SEND_ERROR;
         }
         continue;
-      }
-      else if(outlen == NGTCP2_ERR_WRITE_MORE) {
+      case NGTCP2_ERR_STREAM_SHUT_WR:
+        assert(ndatalen == -1);
+        rv = nghttp3_conn_shutdown_stream_write(qs->h3conn, stream_id);
+        if(rv) {
+          failf(data,
+                "nghttp3_conn_shutdown_stream_write returned error: %s\n",
+                nghttp3_strerror(rv));
+          return CURLE_SEND_ERROR;
+        }
+        continue;
+      case NGTCP2_ERR_WRITE_MORE:
         assert(ndatalen >= 0);
         rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
         if(rv) {
@@ -1838,8 +1792,7 @@ static CURLcode ng_flush_egress(struct Curl_easy *data,
           return CURLE_SEND_ERROR;
         }
         continue;
-      }
-      else {
+      default:
         assert(ndatalen == -1);
         failf(data, "ngtcp2_conn_writev_stream returned error: %s",
               ngtcp2_strerror((int)outlen));
index cbede45..5014530 100644 (file)
 #include <gnutls/gnutls.h>
 #endif
 
-struct quic_handshake {
-  char *buf;       /* pointer to the buffer */
-  size_t alloclen; /* size of allocation */
-  size_t len;      /* size of content in buffer */
-  size_t nread;    /* how many bytes have been read */
-};
-
 struct quicsocket {
   struct connectdata *conn; /* point back to the connection */
   ngtcp2_conn *qconn;
@@ -56,7 +49,6 @@ struct quicsocket {
   gnutls_certificate_credentials_t cred;
   gnutls_session_t ssl;
 #endif
-  struct quic_handshake crypto_data[3];
   /* the last TLS alert description generated by the local endpoint */
   uint8_t tls_alert;
   struct sockaddr_storage local_addr;
index b62d884..f757760 100644 (file)
@@ -258,7 +258,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
 
-  infof(data, "Connect socket %d over QUIC to %s:%ld\n",
+  infof(data, "Connect socket %d over QUIC to %s:%ld",
         sockfd, ipbuf, port);
 
   Curl_persistconninfo(data, conn, NULL, -1);
@@ -277,7 +277,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
       offset += 1 + alpn_len;
     }
 
-    infof(data, "Sent QUIC client Initial, ALPN: %s\n",
+    infof(data, "Sent QUIC client Initial, ALPN: %s",
           alpn_protocols + 1);
   }
 
@@ -345,7 +345,7 @@ CURLcode Curl_quic_is_connected(struct Curl_easy *data,
   if(quiche_conn_is_established(qs->conn)) {
     *done = TRUE;
     result = quiche_has_connected(conn, 0, sockindex);
-    DEBUGF(infof(data, "quiche established connection!\n"));
+    DEBUGF(infof(data, "quiche established connection!"));
   }
 
   return result;
@@ -422,10 +422,9 @@ static CURLcode flush_egress(struct Curl_easy *data, int sockfd,
       return CURLE_SEND_ERROR;
     }
 
-    sent = sendto(sockfd, out, sent, 0,
-                  (struct sockaddr *)&send_info.to, send_info.to_len);
+    sent = send(sockfd, out, sent, 0);
     if(sent < 0) {
-      failf(data, "sendto() returned %zd", sent);
+      failf(data, "send() returned %zd", sent);
       return CURLE_SEND_ERROR;
     }
   } while(1);
@@ -492,7 +491,7 @@ static ssize_t h3_stream_recv(struct Curl_easy *data,
   headers.nlen = 0;
 
   if(process_ingress(data, sockfd, qs)) {
-    infof(data, "h3_stream_recv returns on ingress\n");
+    infof(data, "h3_stream_recv returns on ingress");
     *curlcode = CURLE_RECV_ERROR;
     return -1;
   }
@@ -505,7 +504,7 @@ static ssize_t h3_stream_recv(struct Curl_easy *data,
 
     if(s != stream->stream3_id) {
       /* another transfer, ignore for now */
-      infof(data, "Got h3 for stream %u, expects %u\n",
+      infof(data, "Got h3 for stream %u, expects %u",
             s, stream->stream3_id);
       continue;
     }
@@ -586,7 +585,7 @@ static ssize_t h3_stream_send(struct Curl_easy *data,
     sent = len;
   }
   else {
-    H3BUGF(infof(data, "Pass on %zd body bytes to quiche\n", len));
+    H3BUGF(infof(data, "Pass on %zd body bytes to quiche", len));
     sent = quiche_h3_send_body(qs->h3c, qs->conn, stream->stream3_id,
                                (uint8_t *)mem, len, FALSE);
     if(sent < 0) {
@@ -605,12 +604,11 @@ static ssize_t h3_stream_send(struct Curl_easy *data,
 }
 
 /*
- * Store quiche version info in this buffer, Prefix with a space.  Return total
- * length written.
+ * Store quiche version info in this buffer.
  */
-int Curl_quic_ver(char *p, size_t len)
+void Curl_quic_ver(char *p, size_t len)
 {
-  return msnprintf(p, len, "quiche/%s", quiche_version());
+  (void)msnprintf(p, len, "quiche/%s", quiche_version());
 }
 
 /* Index where :authority header field will appear in request header
@@ -780,7 +778,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
     for(i = 0; i < nheader; ++i) {
       acc += nva[i].name_len + nva[i].value_len;
 
-      H3BUGF(infof(data, "h3 [%.*s: %.*s]\n",
+      H3BUGF(infof(data, "h3 [%.*s: %.*s]",
                    nva[i].name_len, nva[i].name,
                    nva[i].value_len, nva[i].value));
     }
@@ -788,7 +786,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
     if(acc > MAX_ACC) {
       infof(data, "http_request: Warning: The cumulative length of all "
             "headers exceeds %d bytes and that could cause the "
-            "stream to be rejected.\n", MAX_ACC);
+            "stream to be rejected.", MAX_ACC);
     }
   }
 
@@ -825,13 +823,13 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
   Curl_safefree(nva);
 
   if(stream3_id < 0) {
-    H3BUGF(infof(data, "quiche_h3_send_request returned %d\n",
+    H3BUGF(infof(data, "quiche_h3_send_request returned %d",
                  stream3_id));
     result = CURLE_SEND_ERROR;
     goto fail;
   }
 
-  infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)\n",
+  infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)",
         stream3_id, (void *)data);
   stream->stream3_id = stream3_id;
 
index d146d15..3e317e8 100644 (file)
@@ -74,7 +74,6 @@
 #include "strcase.h"
 #include "vtls/vtls.h"
 #include "connect.h"
-#include "strerror.h"
 #include "inet_ntop.h"
 #include "parsedate.h"          /* for the week day and month names */
 #include "sockaddr.h"           /* required for Curl_sockaddr_storage */
@@ -303,7 +302,7 @@ static void mystate(struct Curl_easy *data, sshstate nowstate
 
 
   if(sshc->state != nowstate) {
-    infof(data, "SSH %p state change from %s to %s (line %d)\n",
+    infof(data, "SSH %p state change from %s to %s (line %d)",
           (void *) sshc, names[sshc->state], names[nowstate],
           lineno);
   }
@@ -368,7 +367,7 @@ static int myssh_is_known(struct Curl_easy *data)
     for(i = 0; i < 16; i++)
       msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]);
 
-    infof(data, "SSH MD5 fingerprint: %s\n", md5buffer);
+    infof(data, "SSH MD5 fingerprint: %s", md5buffer);
 
     if(!strcasecompare(md5buffer, pubkey_md5)) {
       failf(data,
@@ -732,7 +731,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
 
         if(rc == SSH_AUTH_SUCCESS) {
           sshc->authed = TRUE;
-          infof(data, "Authenticated with none\n");
+          infof(data, "Authenticated with none");
           state(data, SSH_AUTH_DONE);
           break;
         }
@@ -744,7 +743,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
         sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL);
         if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
           state(data, SSH_AUTH_PKEY_INIT);
-          infof(data, "Authentication using SSH public key file\n");
+          infof(data, "Authentication using SSH public key file");
         }
         else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
           state(data, SSH_AUTH_GSSAPI);
@@ -810,7 +809,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
         if(rc == SSH_AUTH_SUCCESS) {
           rc = SSH_OK;
           sshc->authed = TRUE;
-          infof(data, "Completed public key authentication\n");
+          infof(data, "Completed public key authentication");
           state(data, SSH_AUTH_DONE);
           break;
         }
@@ -827,12 +826,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
 
       if(rc == SSH_AUTH_SUCCESS) {
         sshc->authed = TRUE;
-        infof(data, "Completed public key authentication\n");
+        infof(data, "Completed public key authentication");
         state(data, SSH_AUTH_DONE);
         break;
       }
       else {
-        infof(data, "Failed public key authentication (rc: %d)\n", rc);
+        infof(data, "Failed public key authentication (rc: %d)", rc);
         MOVE_TO_SECONDARY_AUTH;
       }
       break;
@@ -852,7 +851,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
       if(rc == SSH_AUTH_SUCCESS) {
         rc = SSH_OK;
         sshc->authed = TRUE;
-        infof(data, "Completed gssapi authentication\n");
+        infof(data, "Completed gssapi authentication");
         state(data, SSH_AUTH_DONE);
         break;
       }
@@ -878,7 +877,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
       }
       if(rc == SSH_OK) {
         sshc->authed = TRUE;
-        infof(data, "completed keyboard interactive authentication\n");
+        infof(data, "completed keyboard interactive authentication");
       }
       state(data, SSH_AUTH_DONE);
       break;
@@ -901,7 +900,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
 
       if(rc == SSH_AUTH_SUCCESS) {
         sshc->authed = TRUE;
-        infof(data, "Completed password authentication\n");
+        infof(data, "Completed password authentication");
         state(data, SSH_AUTH_DONE);
       }
       else {
@@ -919,7 +918,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
       /*
        * At this point we have an authenticated ssh session.
        */
-      infof(data, "Authentication complete\n");
+      infof(data, "Authentication complete");
 
       Curl_pgrsTime(data, TIMER_APPCONNECT);      /* SSH is connected */
 
@@ -930,7 +929,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
         state(data, SSH_SFTP_INIT);
         break;
       }
-      infof(data, "SSH CONNECT phase done\n");
+      infof(data, "SSH CONNECT phase done");
       state(data, SSH_STOP);
       break;
 
@@ -970,7 +969,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
          we get the homedir here, we get the "workingpath" in the DO action
          since the homedir will remain the same between request but the
          working path will not. */
-      DEBUGF(infof(data, "SSH CONNECT phase done\n"));
+      DEBUGF(infof(data, "SSH CONNECT phase done"));
       state(data, SSH_STOP);
       break;
 
@@ -983,7 +982,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
       }
 
       if(data->set.quote) {
-        infof(data, "Sending quote commands\n");
+        infof(data, "Sending quote commands");
         sshc->quote_item = data->set.quote;
         state(data, SSH_SFTP_QUOTE);
       }
@@ -994,7 +993,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
 
     case SSH_SFTP_POSTQUOTE_INIT:
       if(data->set.postquote) {
-        infof(data, "Sending quote commands\n");
+        infof(data, "Sending quote commands");
         sshc->quote_item = data->set.postquote;
         state(data, SSH_SFTP_QUOTE);
       }
@@ -1367,7 +1366,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
       if(sshc->slash_pos) {
         *sshc->slash_pos = 0;
 
-        infof(data, "Creating directory '%s'\n", protop->path);
+        infof(data, "Creating directory '%s'", protop->path);
         state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
         break;
       }
@@ -1731,7 +1730,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
     if(data->req.size == 0) {
       /* no data to transfer */
       Curl_setup_transfer(data, -1, -1, FALSE, -1);
-      infof(data, "File already completely downloaded\n");
+      infof(data, "File already completely downloaded");
       state(data, SSH_STOP);
       break;
     }
@@ -1764,7 +1763,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
       }
       Curl_safefree(protop->path);
 
-      DEBUGF(infof(data, "SFTP DONE done\n"));
+      DEBUGF(infof(data, "SFTP DONE done"));
 
       /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
          After nextstate is executed, the control should come back to
@@ -1933,7 +1932,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
           break;
         }
         if(rc != SSH_OK) {
-          infof(data, "Failed to close libssh scp channel: %s\n",
+          infof(data, "Failed to close libssh scp channel: %s",
                 ssh_get_error(sshc->ssh_session));
         }
       }
@@ -1946,7 +1945,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
         ssh_scp_free(sshc->scp_session);
         sshc->scp_session = NULL;
       }
-      DEBUGF(infof(data, "SCP DONE phase complete\n"));
+      DEBUGF(infof(data, "SCP DONE phase complete"));
 
       ssh_set_blocking(sshc->ssh_session, 0);
 
@@ -2213,7 +2212,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
   }
 
   if(conn->user && conn->user[0] != '\0') {
-    infof(data, "User: %s\n", conn->user);
+    infof(data, "User: %s", conn->user);
     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
     if(rc != SSH_OK) {
       failf(data, "Could not set user");
@@ -2222,7 +2221,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
   }
 
   if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
-    infof(data, "Known hosts: %s\n", data->set.str[STRING_SSH_KNOWNHOSTS]);
+    infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
     rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
                          data->set.str[STRING_SSH_KNOWNHOSTS]);
     if(rc != SSH_OK) {
@@ -2279,7 +2278,7 @@ static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
   result = myssh_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
   return result;
 }
@@ -2300,7 +2299,7 @@ CURLcode scp_perform(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
 
-  DEBUGF(infof(data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts"));
 
   *dophase_done = FALSE;        /* not done yet */
 
@@ -2312,7 +2311,7 @@ CURLcode scp_perform(struct Curl_easy *data,
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
 
   return result;
@@ -2481,7 +2480,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
 
-  DEBUGF(infof(data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts"));
 
   *dophase_done = FALSE; /* not done yet */
 
@@ -2494,7 +2493,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
 
   return result;
@@ -2506,7 +2505,7 @@ static CURLcode sftp_doing(struct Curl_easy *data,
 {
   CURLcode result = myssh_multi_statemach(data, dophase_done);
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
   return result;
 }
@@ -2521,7 +2520,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   (void) dead_connection;
 
-  DEBUGF(infof(data, "SSH DISCONNECT starts now\n"));
+  DEBUGF(infof(data, "SSH DISCONNECT starts now"));
 
   if(conn->proto.sshc.ssh_session) {
     /* only if there's a session still around to use! */
@@ -2529,7 +2528,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
     result = myssh_block_statemach(data, TRUE);
   }
 
-  DEBUGF(infof(data, "SSH DISCONNECT is done\n"));
+  DEBUGF(infof(data, "SSH DISCONNECT is done"));
 
   return result;
 
@@ -2940,9 +2939,9 @@ void Curl_ssh_cleanup(void)
   (void)ssh_finalize();
 }
 
-size_t Curl_ssh_version(char *buffer, size_t buflen)
+void Curl_ssh_version(char *buffer, size_t buflen)
 {
-  return msnprintf(buffer, buflen, "libssh/%s", CURL_LIBSSH_VERSION);
+  (void)msnprintf(buffer, buflen, "libssh/%s", CURL_LIBSSH_VERSION);
 }
 
 #endif                          /* USE_LIBSSH */
index 8a6345b..a772f1f 100644 (file)
@@ -73,7 +73,6 @@
 #include "strcase.h"
 #include "vtls/vtls.h"
 #include "connect.h"
-#include "strerror.h"
 #include "inet_ntop.h"
 #include "parsedate.h" /* for the week day and month names */
 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
@@ -378,7 +377,7 @@ static void state(struct Curl_easy *data, sshstate nowstate)
   DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
 
   if(sshc->state != nowstate) {
-    infof(data, "SFTP %p state change from %s to %s\n",
+    infof(data, "SFTP %p state change from %s to %s",
           (void *)sshc, names[sshc->state], names[nowstate]);
   }
 #endif
@@ -491,7 +490,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
         break;
 #endif
       default:
-        infof(data, "unsupported key type, can't check knownhosts!\n");
+        infof(data, "unsupported key type, can't check knownhosts!");
         keybit = 0;
         break;
       }
@@ -519,7 +518,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
                                            &host);
 #endif
 
-        infof(data, "SSH host check: %d, key: %s\n", keycheck,
+        infof(data, "SSH host check: %d, key: %s", keycheck,
               (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
               host->key:"<none>");
 
@@ -586,7 +585,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
                                           LIBSSH2_KNOWNHOST_KEYENC_RAW|
                                           keybit, NULL);
         if(addrc)
-          infof(data, "Warning adding the known host %s failed!\n",
+          infof(data, "Warning adding the known host %s failed!",
                 conn->host.name);
         else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE ||
                 rc == CURLKHSTAT_FINE_REPLACE) {
@@ -597,7 +596,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
                                         data->set.str[STRING_SSH_KNOWNHOSTS],
                                         LIBSSH2_KNOWNHOST_FILE_OPENSSH);
           if(wrc) {
-            infof(data, "Warning, writing %s failed!\n",
+            infof(data, "Warning, writing %s failed!",
                   data->set.str[STRING_SSH_KNOWNHOSTS]);
           }
         }
@@ -626,7 +625,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
     int i;
     for(i = 0; i < 16; i++)
       msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
-    infof(data, "SSH MD5 fingerprint: %s\n", md5buffer);
+    infof(data, "SSH MD5 fingerprint: %s", md5buffer);
   }
 
   /* Before we authenticate we check the hostkey's MD5 fingerprint
@@ -645,7 +644,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
       sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
       return sshc->actualcode;
     }
-    infof(data, "MD5 checksum match!\n");
+    infof(data, "MD5 checksum match!");
     /* as we already matched, we skip the check for known hosts */
     return CURLE_OK;
   }
@@ -702,7 +701,7 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
           if(store->name[0] == '[') {
             kh_name_end = strstr(store->name, "]:");
             if(!kh_name_end) {
-              infof(data, "Invalid host pattern %s in %s\n",
+              infof(data, "Invalid host pattern %s in %s",
                     store->name, data->set.str[STRING_SSH_KNOWNHOSTS]);
               continue;
             }
@@ -729,7 +728,7 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
     }
 
     if(found) {
-      infof(data, "Found host %s in %s\n",
+      infof(data, "Found host %s in %s",
             conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
 
       switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) {
@@ -768,13 +767,13 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
         return CURLE_SSH;
       }
 
-      infof(data, "Set \"%s\" as SSH hostkey type\n", hostkey_method);
+      infof(data, "Set \"%s\" as SSH hostkey type", hostkey_method);
       result = libssh2_session_error_to_CURLE(
         libssh2_session_method_pref(
           sshc->ssh_session, LIBSSH2_METHOD_HOSTKEY, hostkey_method));
     }
     else {
-      infof(data, "Did not find host %s in %s\n",
+      infof(data, "Did not find host %s in %s",
             conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
     }
   }
@@ -874,7 +873,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
       if(!sshc->authlist) {
         if(libssh2_userauth_authenticated(sshc->ssh_session)) {
           sshc->authed = TRUE;
-          infof(data, "SSH user accepted with no authentication\n");
+          infof(data, "SSH user accepted with no authentication");
           state(data, SSH_AUTH_DONE);
           break;
         }
@@ -887,7 +886,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
         }
         break;
       }
-      infof(data, "SSH authentication methods available: %s\n",
+      infof(data, "SSH authentication methods available: %s",
             sshc->authlist);
 
       state(data, SSH_AUTH_PKEY_INIT);
@@ -972,8 +971,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
           sshc->passphrase = "";
 
         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);
+          infof(data, "Using SSH public key file '%s'", sshc->rsa_pub);
+        infof(data, "Using SSH private key file '%s'", sshc->rsa);
 
         state(data, SSH_AUTH_PKEY);
       }
@@ -1000,14 +999,14 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
 
       if(rc == 0) {
         sshc->authed = TRUE;
-        infof(data, "Initialized SSH public key authentication\n");
+        infof(data, "Initialized SSH public key authentication");
         state(data, SSH_AUTH_DONE);
       }
       else {
         char *err_msg = NULL;
         (void)libssh2_session_last_error(sshc->ssh_session,
                                          &err_msg, NULL, 0);
-        infof(data, "SSH public key authentication failed: %s\n", err_msg);
+        infof(data, "SSH public key authentication failed: %s", err_msg);
         state(data, SSH_AUTH_PASS_INIT);
         rc = 0; /* clear rc and continue */
       }
@@ -1035,7 +1034,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
       }
       if(rc == 0) {
         sshc->authed = TRUE;
-        infof(data, "Initialized password authentication\n");
+        infof(data, "Initialized password authentication");
         state(data, SSH_AUTH_DONE);
       }
       else {
@@ -1069,7 +1068,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
         if(!sshc->ssh_agent) {
           sshc->ssh_agent = libssh2_agent_init(sshc->ssh_session);
           if(!sshc->ssh_agent) {
-            infof(data, "Could not create agent object\n");
+            infof(data, "Could not create agent object");
 
             state(data, SSH_AUTH_KEY_INIT);
             break;
@@ -1080,7 +1079,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
         if(rc == LIBSSH2_ERROR_EAGAIN)
           break;
         if(rc < 0) {
-          infof(data, "Failure connecting to agent\n");
+          infof(data, "Failure connecting to agent");
           state(data, SSH_AUTH_KEY_INIT);
           rc = 0; /* clear rc and continue */
         }
@@ -1100,7 +1099,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
       if(rc == LIBSSH2_ERROR_EAGAIN)
         break;
       if(rc < 0) {
-        infof(data, "Failure requesting identities to agent\n");
+        infof(data, "Failure requesting identities to agent");
         state(data, SSH_AUTH_KEY_INIT);
         rc = 0; /* clear rc and continue */
       }
@@ -1136,13 +1135,13 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
       }
 
       if(rc < 0)
-        infof(data, "Failure requesting identities to agent\n");
+        infof(data, "Failure requesting identities to agent");
       else if(rc == 1)
-        infof(data, "No identity would match\n");
+        infof(data, "No identity would match");
 
       if(rc == LIBSSH2_ERROR_NONE) {
         sshc->authed = TRUE;
-        infof(data, "Agent based authentication successful\n");
+        infof(data, "Agent based authentication successful");
         state(data, SSH_AUTH_DONE);
       }
       else {
@@ -1174,7 +1173,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
       }
       if(rc == 0) {
         sshc->authed = TRUE;
-        infof(data, "Initialized keyboard interactive authentication\n");
+        infof(data, "Initialized keyboard interactive authentication");
       }
       state(data, SSH_AUTH_DONE);
       break;
@@ -1190,7 +1189,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
       /*
        * At this point we have an authenticated ssh session.
        */
-      infof(data, "Authentication complete\n");
+      infof(data, "Authentication complete");
 
       Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */
 
@@ -1201,7 +1200,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
         state(data, SSH_SFTP_INIT);
         break;
       }
-      infof(data, "SSH CONNECT phase done\n");
+      infof(data, "SSH CONNECT phase done");
       state(data, SSH_STOP);
       break;
 
@@ -1261,7 +1260,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
              a time-out or similar */
           result = CURLE_SSH;
         sshc->actualcode = result;
-        DEBUGF(infof(data, "error = %lu makes libcurl = %d\n",
+        DEBUGF(infof(data, "error = %lu makes libcurl = %d",
                      sftperr, (int)result));
         state(data, SSH_STOP);
         break;
@@ -1271,7 +1270,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
        we get the homedir here, we get the "workingpath" in the DO action
        since the homedir will remain the same between request but the
        working path will not. */
-    DEBUGF(infof(data, "SSH CONNECT phase done\n"));
+    DEBUGF(infof(data, "SSH CONNECT phase done"));
     state(data, SSH_STOP);
     break;
 
@@ -1285,7 +1284,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
       }
 
       if(data->set.quote) {
-        infof(data, "Sending quote commands\n");
+        infof(data, "Sending quote commands");
         sshc->quote_item = data->set.quote;
         state(data, SSH_SFTP_QUOTE);
       }
@@ -1296,7 +1295,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
 
     case SSH_SFTP_POSTQUOTE_INIT:
       if(data->set.postquote) {
-        infof(data, "Sending quote commands\n");
+        infof(data, "Sending quote commands");
         sshc->quote_item = data->set.postquote;
         state(data, SSH_SFTP_QUOTE);
       }
@@ -2048,7 +2047,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
       if(sshc->slash_pos) {
         *sshc->slash_pos = 0;
 
-        infof(data, "Creating directory '%s'\n", sshp->path);
+        infof(data, "Creating directory '%s'", sshp->path);
         state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
         break;
       }
@@ -2411,7 +2410,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
     if(data->req.size == 0) {
       /* no data to transfer */
       Curl_setup_transfer(data, -1, -1, FALSE, -1);
-      infof(data, "File already completely downloaded\n");
+      infof(data, "File already completely downloaded");
       state(data, SSH_STOP);
       break;
     }
@@ -2446,14 +2445,14 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
           char *err_msg = NULL;
           (void)libssh2_session_last_error(sshc->ssh_session,
                                            &err_msg, NULL, 0);
-          infof(data, "Failed to close libssh2 file: %d %s\n", rc, err_msg);
+          infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
         }
         sshc->sftp_handle = NULL;
       }
 
       Curl_safefree(sshp->path);
 
-      DEBUGF(infof(data, "SFTP DONE done\n"));
+      DEBUGF(infof(data, "SFTP DONE done"));
 
       /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
          After nextstate is executed, the control should come back to
@@ -2483,7 +2482,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
           char *err_msg = NULL;
           (void)libssh2_session_last_error(sshc->ssh_session, &err_msg,
                                            NULL, 0);
-          infof(data, "Failed to close libssh2 file: %d %s\n", rc, err_msg);
+          infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
         }
         sshc->sftp_handle = NULL;
       }
@@ -2493,7 +2492,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
           break;
         }
         if(rc < 0) {
-          infof(data, "Failed to stop libssh2 sftp subsystem\n");
+          infof(data, "Failed to stop libssh2 sftp subsystem");
         }
         sshc->sftp_session = NULL;
       }
@@ -2668,7 +2667,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
           char *err_msg = NULL;
           (void)libssh2_session_last_error(sshc->ssh_session,
                                            &err_msg, NULL, 0);
-          infof(data, "Failed to send libssh2 channel EOF: %d %s\n",
+          infof(data, "Failed to send libssh2 channel EOF: %d %s",
                 rc, err_msg);
         }
       }
@@ -2685,7 +2684,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
           char *err_msg = NULL;
           (void)libssh2_session_last_error(sshc->ssh_session,
                                            &err_msg, NULL, 0);
-          infof(data, "Failed to get channel EOF: %d %s\n", rc, err_msg);
+          infof(data, "Failed to get channel EOF: %d %s", rc, err_msg);
         }
       }
       state(data, SSH_SCP_WAIT_CLOSE);
@@ -2701,7 +2700,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
           char *err_msg = NULL;
           (void)libssh2_session_last_error(sshc->ssh_session,
                                            &err_msg, NULL, 0);
-          infof(data, "Channel failed to close: %d %s\n", rc, err_msg);
+          infof(data, "Channel failed to close: %d %s", rc, err_msg);
         }
       }
       state(data, SSH_SCP_CHANNEL_FREE);
@@ -2717,12 +2716,12 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
           char *err_msg = NULL;
           (void)libssh2_session_last_error(sshc->ssh_session,
                                            &err_msg, NULL, 0);
-          infof(data, "Failed to free libssh2 scp subsystem: %d %s\n",
+          infof(data, "Failed to free libssh2 scp subsystem: %d %s",
                 rc, err_msg);
         }
         sshc->ssh_channel = NULL;
       }
-      DEBUGF(infof(data, "SCP DONE phase complete\n"));
+      DEBUGF(infof(data, "SCP DONE phase complete"));
 #if 0 /* PREV */
       state(data, SSH_SESSION_DISCONNECT);
 #endif
@@ -2743,7 +2742,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
           char *err_msg = NULL;
           (void)libssh2_session_last_error(sshc->ssh_session,
                                            &err_msg, NULL, 0);
-          infof(data, "Failed to free libssh2 scp subsystem: %d %s\n",
+          infof(data, "Failed to free libssh2 scp subsystem: %d %s",
                 rc, err_msg);
         }
         sshc->ssh_channel = NULL;
@@ -2758,7 +2757,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
           char *err_msg = NULL;
           (void)libssh2_session_last_error(sshc->ssh_session,
                                            &err_msg, NULL, 0);
-          infof(data, "Failed to disconnect libssh2 session: %d %s\n",
+          infof(data, "Failed to disconnect libssh2 session: %d %s",
                 rc, err_msg);
         }
       }
@@ -2787,7 +2786,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
           char *err_msg = NULL;
           (void)libssh2_session_last_error(sshc->ssh_session,
                                            &err_msg, NULL, 0);
-          infof(data, "Failed to disconnect from libssh2 agent: %d %s\n",
+          infof(data, "Failed to disconnect from libssh2 agent: %d %s",
                 rc, err_msg);
         }
         libssh2_agent_free(sshc->ssh_agent);
@@ -2809,7 +2808,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
           char *err_msg = NULL;
           (void)libssh2_session_last_error(sshc->ssh_session,
                                            &err_msg, NULL, 0);
-          infof(data, "Failed to free libssh2 session: %d %s\n", rc, err_msg);
+          infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg);
         }
         sshc->ssh_session = NULL;
       }
@@ -2938,6 +2937,7 @@ static CURLcode ssh_block_statemach(struct Curl_easy *data,
 {
   struct ssh_conn *sshc = &conn->proto.sshc;
   CURLcode result = CURLE_OK;
+  struct curltime dis = Curl_now();
 
   while((sshc->state != SSH_STOP) && !result) {
     bool block;
@@ -2962,6 +2962,12 @@ static CURLcode ssh_block_statemach(struct Curl_easy *data,
         return CURLE_OPERATION_TIMEDOUT;
       }
     }
+    else if(Curl_timediff(now, dis) > 1000) {
+      /* disconnect timeout */
+      failf(data, "Disconnect timed out");
+      result = CURLE_OK;
+      break;
+    }
 
     if(block) {
       int dir = libssh2_session_block_directions(sshc->ssh_session);
@@ -3078,10 +3084,10 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
 
 #ifdef CURL_LIBSSH2_DEBUG
   if(conn->user) {
-    infof(data, "User: %s\n", conn->user);
+    infof(data, "User: %s", conn->user);
   }
   if(conn->passwd) {
-    infof(data, "Password: %s\n", conn->passwd);
+    infof(data, "Password: %s", conn->passwd);
   }
   sock = conn->sock[FIRSTSOCKET];
 #endif /* CURL_LIBSSH2_DEBUG */
@@ -3115,7 +3121,7 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
     sshrecv.recvptr = ssh_tls_recv;
     sshsend.sendptr = ssh_tls_send;
 
-    infof(data, "Uses HTTPS proxy!\n");
+    infof(data, "Uses HTTPS proxy!");
     /*
       Setup libssh2 callbacks to make it read/write TLS from the socket.
 
@@ -3153,7 +3159,7 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
 #if LIBSSH2_VERSION_NUM >= 0x010208
     if(libssh2_session_flag(sshc->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0)
 #endif
-      infof(data, "Failed to enable compression for ssh session\n");
+      infof(data, "Failed to enable compression for ssh session");
   }
 
 #ifdef HAVE_LIBSSH2_KNOWNHOST_API
@@ -3171,14 +3177,14 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
                                     data->set.str[STRING_SSH_KNOWNHOSTS],
                                     LIBSSH2_KNOWNHOST_FILE_OPENSSH);
     if(rc < 0)
-      infof(data, "Failed to read known hosts from %s\n",
+      infof(data, "Failed to read known hosts from %s",
             data->set.str[STRING_SSH_KNOWNHOSTS]);
   }
 #endif /* HAVE_LIBSSH2_KNOWNHOST_API */
 
 #ifdef CURL_LIBSSH2_DEBUG
   libssh2_trace(sshc->ssh_session, ~0);
-  infof(data, "SSH socket: %d\n", (int)sock);
+  infof(data, "SSH socket: %d", (int)sock);
 #endif /* CURL_LIBSSH2_DEBUG */
 
   state(data, SSH_INIT);
@@ -3205,7 +3211,7 @@ CURLcode scp_perform(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
 
-  DEBUGF(infof(data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts"));
 
   *dophase_done = FALSE; /* not done yet */
 
@@ -3218,7 +3224,7 @@ CURLcode scp_perform(struct Curl_easy *data,
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
 
   return result;
@@ -3232,7 +3238,7 @@ static CURLcode scp_doing(struct Curl_easy *data,
   result = ssh_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
   return result;
 }
@@ -3394,7 +3400,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
 {
   CURLcode result = CURLE_OK;
 
-  DEBUGF(infof(data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts"));
 
   *dophase_done = FALSE; /* not done yet */
 
@@ -3407,7 +3413,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
   *connected = data->conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
 
   return result;
@@ -3420,7 +3426,7 @@ static CURLcode sftp_doing(struct Curl_easy *data,
   CURLcode result = ssh_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
   return result;
 }
@@ -3435,7 +3441,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
   struct ssh_conn *sshc = &conn->proto.sshc;
   (void) dead_connection;
 
-  DEBUGF(infof(data, "SSH DISCONNECT starts now\n"));
+  DEBUGF(infof(data, "SSH DISCONNECT starts now"));
 
   if(sshc->ssh_session) {
     /* only if there's a session still around to use! */
@@ -3443,7 +3449,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
     result = ssh_block_statemach(data, conn, TRUE);
   }
 
-  DEBUGF(infof(data, "SSH DISCONNECT is done\n"));
+  DEBUGF(infof(data, "SSH DISCONNECT is done"));
 
   return result;
 
@@ -3602,9 +3608,9 @@ void Curl_ssh_cleanup(void)
 #endif
 }
 
-size_t Curl_ssh_version(char *buffer, size_t buflen)
+void Curl_ssh_version(char *buffer, size_t buflen)
 {
-  return msnprintf(buffer, buflen, "libssh2/%s", LIBSSH2_VERSION);
+  (void)msnprintf(buffer, buflen, "libssh2/%s", LIBSSH2_VERSION);
 }
 
 /* The SSH session is associated with the *CONNECTION* but the callback user
index 505b078..7972081 100644 (file)
@@ -262,7 +262,7 @@ extern const struct Curl_handler Curl_handler_sftp;
 /* generic SSH backend functions */
 CURLcode Curl_ssh_init(void);
 void Curl_ssh_cleanup(void);
-size_t Curl_ssh_version(char *buffer, size_t buflen);
+void Curl_ssh_version(char *buffer, size_t buflen);
 void Curl_ssh_attach(struct Curl_easy *data,
                      struct connectdata *conn);
 #else
index 9f3266a..4b1e2ec 100644 (file)
@@ -205,7 +205,7 @@ static void state(struct Curl_easy *data, sshstate nowstate)
   DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
 
   if(sshc->state != nowstate) {
-    infof(data, "wolfssh %p state change from %s to %s\n",
+    infof(data, "wolfssh %p state change from %s to %s",
           (void *)sshc, names[sshc->state], names[nowstate]);
   }
 #endif
@@ -274,7 +274,7 @@ static ssize_t wsftp_send(struct Curl_easy *data, int sockindex,
     return -1;
   }
   DEBUGASSERT(rc == (int)len);
-  infof(data, "sent %zd bytes SFTP from offset %zd\n",
+  infof(data, "sent %zd bytes SFTP from offset %zd",
         len, sshc->offset);
   sshc->offset += len;
   return (ssize_t)rc;
@@ -348,7 +348,7 @@ static int userauth(byte authtype,
                     void *ctx)
 {
   struct Curl_easy *data = ctx;
-  DEBUGF(infof(data, "wolfssh callback: type %s\n",
+  DEBUGF(infof(data, "wolfssh callback: type %s",
                authtype == WOLFSSH_USERAUTH_PASSWORD ? "PASSWORD" :
                "PUBLICCKEY"));
   if(authtype == WOLFSSH_USERAUTH_PASSWORD) {
@@ -468,7 +468,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
         state(data, SSH_STOP);
         return CURLE_SSH;
       }
-      infof(data, "wolfssh connected!\n");
+      infof(data, "wolfssh connected!");
       state(data, SSH_STOP);
       break;
     case SSH_STOP:
@@ -489,7 +489,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
         return CURLE_OK;
       }
       else if(rc == WS_SUCCESS) {
-        infof(data, "wolfssh SFTP connected!\n");
+        infof(data, "wolfssh SFTP connected!");
         state(data, SSH_SFTP_REALPATH);
       }
       else {
@@ -518,7 +518,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
         else {
           memcpy(sshc->homedir, name->fName, name->fSz);
           sshc->homedir[name->fSz] = 0;
-          infof(data, "wolfssh SFTP realpath succeeded!\n");
+          infof(data, "wolfssh SFTP realpath succeeded!");
         }
         wolfSSH_SFTPNAME_list_free(name);
         state(data, SSH_STOP);
@@ -536,7 +536,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
       }
 
       if(data->set.quote) {
-        infof(data, "Sending quote commands\n");
+        infof(data, "Sending quote commands");
         sshc->quote_item = data->set.quote;
         state(data, SSH_SFTP_QUOTE);
       }
@@ -616,7 +616,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
         return CURLE_OK;
       }
       else if(rc == WS_SUCCESS) {
-        infof(data, "wolfssh SFTP open succeeded!\n");
+        infof(data, "wolfssh SFTP open succeeded!");
       }
       else {
         failf(data, "wolfssh SFTP upload open failed: %d", rc);
@@ -727,7 +727,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
         return CURLE_OK;
       }
       else if(rc == WS_SUCCESS) {
-        infof(data, "wolfssh SFTP open succeeded!\n");
+        infof(data, "wolfssh SFTP open succeeded!");
         state(data, SSH_SFTP_DOWNLOAD_STAT);
         return CURLE_OK;
       }
@@ -753,7 +753,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
         return CURLE_OK;
       }
       else if(rc == WS_SUCCESS) {
-        infof(data, "wolfssh STAT succeeded!\n");
+        infof(data, "wolfssh STAT succeeded!");
       }
       else {
         failf(data, "wolfssh SFTP open failed: %d", rc);
@@ -769,12 +769,12 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
       data->req.maxdownload = size;
       Curl_pgrsSetDownloadSize(data, size);
 
-      infof(data, "SFTP download %" CURL_FORMAT_CURL_OFF_T " bytes\n", size);
+      infof(data, "SFTP download %" CURL_FORMAT_CURL_OFF_T " bytes", size);
 
       /* We cannot seek with wolfSSH so resuming and range requests are not
          possible */
       if(data->state.use_range || data->state.resume_from) {
-        infof(data, "wolfSSH cannot do range/seek on SFTP\n");
+        infof(data, "wolfSSH cannot do range/seek on SFTP");
         return CURLE_BAD_DOWNLOAD_RESUME;
       }
 
@@ -782,7 +782,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
       if(data->req.size == 0) {
         /* no data to transfer */
         Curl_setup_transfer(data, -1, -1, FALSE, -1);
-        infof(data, "File already completely downloaded\n");
+        infof(data, "File already completely downloaded");
         state(data, SSH_STOP);
         break;
       }
@@ -911,7 +911,7 @@ static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done)
     /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
        try again */
     if(*done) {
-      DEBUGF(infof(data, "wssh_statemach_act says DONE\n"));
+      DEBUGF(infof(data, "wssh_statemach_act says DONE"));
     }
   } while(!result && !*done && !block);
 
@@ -937,7 +937,7 @@ CURLcode wsftp_perform(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
 
-  DEBUGF(infof(data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts"));
 
   *dophase_done = FALSE; /* not done yet */
 
@@ -950,7 +950,7 @@ CURLcode wsftp_perform(struct Curl_easy *data,
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
 
   return result;
@@ -1107,7 +1107,7 @@ static CURLcode wsftp_doing(struct Curl_easy *data,
   CURLcode result = wssh_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete"));
   }
   return result;
 }
@@ -1119,7 +1119,7 @@ static CURLcode wsftp_disconnect(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   (void)dead;
 
-  DEBUGF(infof(data, "SSH DISCONNECT starts now\n"));
+  DEBUGF(infof(data, "SSH DISCONNECT starts now"));
 
   if(conn->proto.sshc.ssh_session) {
     /* only if there's a session still around to use! */
@@ -1127,7 +1127,7 @@ static CURLcode wsftp_disconnect(struct Curl_easy *data,
     result = wssh_block_statemach(data, TRUE);
   }
 
-  DEBUGF(infof(data, "SSH DISCONNECT is done\n"));
+  DEBUGF(infof(data, "SSH DISCONNECT is done"));
   return result;
 }
 
@@ -1148,9 +1148,9 @@ static int wssh_getsock(struct Curl_easy *data,
   return bitmap;
 }
 
-size_t Curl_ssh_version(char *buffer, size_t buflen)
+void Curl_ssh_version(char *buffer, size_t buflen)
 {
-  return msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING);
+  (void)msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING);
 }
 
 CURLcode Curl_ssh_init(void)
index 7f72971..e87649e 100644 (file)
@@ -68,6 +68,14 @@ struct cafile_parser {
   size_t dn_len;
 };
 
+#define CAFILE_SOURCE_PATH 1
+#define CAFILE_SOURCE_BLOB 2
+struct cafile_source {
+  const int type;
+  const char * const data;
+  const size_t len;
+};
+
 static void append_dn(void *ctx, const void *buf, size_t len)
 {
   struct cafile_parser *ca = ctx;
@@ -90,7 +98,8 @@ static void x509_push(void *ctx, const void *buf, size_t len)
     br_x509_decoder_push(&ca->xc, buf, len);
 }
 
-static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors,
+static CURLcode load_cafile(struct cafile_source *source,
+                            br_x509_trust_anchor **anchors,
                             size_t *anchors_len)
 {
   struct cafile_parser ca;
@@ -100,13 +109,22 @@ static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors,
   br_x509_trust_anchor *new_anchors;
   size_t new_anchors_len;
   br_x509_pkey *pkey;
-  FILE *fp;
-  unsigned char buf[BUFSIZ], *p;
+  FILE *fp = 0;
+  unsigned char buf[BUFSIZ];
+  const unsigned char *p;
   const char *name;
   size_t n, i, pushed;
 
-  fp = fopen(path, "rb");
-  if(!fp)
+  DEBUGASSERT(source->type == CAFILE_SOURCE_PATH
+              || source->type == CAFILE_SOURCE_BLOB);
+
+  if(source->type == CAFILE_SOURCE_PATH) {
+    fp = fopen(source->data, "rb");
+    if(!fp)
+      return CURLE_SSL_CACERT_BADFILE;
+  }
+
+  if(source->type == CAFILE_SOURCE_BLOB && source->len > (size_t)INT_MAX)
     return CURLE_SSL_CACERT_BADFILE;
 
   ca.err = CURLE_OK;
@@ -115,11 +133,17 @@ static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors,
   ca.anchors_len = 0;
   br_pem_decoder_init(&pc);
   br_pem_decoder_setdest(&pc, x509_push, &ca);
-  for(;;) {
-    n = fread(buf, 1, sizeof(buf), fp);
-    if(n == 0)
-      break;
-    p = buf;
+  do {
+    if(source->type == CAFILE_SOURCE_PATH) {
+      n = fread(buf, 1, sizeof(buf), fp);
+      if(n == 0)
+        break;
+      p = buf;
+    }
+    else if(source->type == CAFILE_SOURCE_BLOB) {
+      n = source->len;
+      p = (unsigned char *) source->data;
+    }
     while(n) {
       pushed = br_pem_decoder_push(&pc, p, n);
       if(ca.err)
@@ -211,12 +235,13 @@ static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors,
         goto fail;
       }
     }
-  }
-  if(ferror(fp))
+  } while(source->type != CAFILE_SOURCE_BLOB);
+  if(fp && ferror(fp))
     ca.err = CURLE_READ_ERROR;
 
 fail:
-  fclose(fp);
+  if(fp)
+    fclose(fp);
   if(ca.err == CURLE_OK) {
     *anchors = ca.anchors;
     *anchors_len = ca.anchors_len;
@@ -299,8 +324,11 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
-  const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
-  const char * const hostname = SSL_HOST_NAME();
+  const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+  const char * const ssl_cafile =
+    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+    (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
+  const char *hostname = SSL_HOST_NAME();
   const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
   const bool verifyhost = SSL_CONN_CONFIG(verifyhost);
   CURLcode ret;
@@ -340,8 +368,30 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
     return CURLE_SSL_CONNECT_ERROR;
   }
 
+  if(ca_info_blob) {
+    struct cafile_source source = {
+      CAFILE_SOURCE_BLOB,
+      ca_info_blob->data,
+      ca_info_blob->len,
+    };
+    ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
+    if(ret != CURLE_OK) {
+      if(verifypeer) {
+        failf(data, "error importing CA certificate blob");
+        return ret;
+      }
+      /* Only warn if no certificate verification is required. */
+      infof(data, "error importing CA certificate blob, continuing anyway");
+    }
+  }
+
   if(ssl_cafile) {
-    ret = load_cafile(ssl_cafile, &backend->anchors, &backend->anchors_len);
+    struct cafile_source source = {
+      CAFILE_SOURCE_PATH,
+      ssl_cafile,
+      0,
+    };
+    ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
     if(ret != CURLE_OK) {
       if(verifypeer) {
         failf(data, "error setting certificate verify locations."
@@ -349,7 +399,7 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
         return ret;
       }
       infof(data, "error setting certificate verify locations,"
-            " continuing anyway:\n");
+            " continuing anyway:");
     }
   }
 
@@ -373,7 +423,7 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
     if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE,
                               &session, NULL, sockindex)) {
       br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
-      infof(data, "BearSSL: re-using session ID\n");
+      infof(data, "BearSSL: re-using session ID");
     }
     Curl_ssl_sessionid_unlock(data);
   }
@@ -392,12 +442,12 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
 #endif
       ) {
       backend->protocols[cur++] = ALPN_H2;
-      infof(data, "ALPN, offering %s\n", ALPN_H2);
+      infof(data, "ALPN, offering %s", ALPN_H2);
     }
 #endif
 
     backend->protocols[cur++] = ALPN_HTTP_1_1;
-    infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+    infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
 
     br_ssl_engine_set_protocol_names(&backend->ctx.eng,
                                      backend->protocols, cur);
@@ -538,7 +588,7 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
 
     protocol = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
     if(protocol) {
-      infof(data, "ALPN, server accepted to use %s\n", protocol);
+      infof(data, "ALPN, server accepted to use %s", protocol);
 
 #ifdef USE_HTTP2
       if(!strcmp(protocol, ALPN_H2))
@@ -548,12 +598,12 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
       if(!strcmp(protocol, ALPN_HTTP_1_1))
         conn->negnpn = CURL_HTTP_VERSION_1_1;
       else
-        infof(data, "ALPN, unrecognized protocol %s\n", protocol);
+        infof(data, "ALPN, unrecognized protocol %s", protocol);
       Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                           BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
     }
     else
-      infof(data, "ALPN, server did not agree to a protocol\n");
+      infof(data, "ALPN, server did not agree to a protocol");
   }
 
   if(SSL_SET_OPTION(primary.sessionid)) {
@@ -840,30 +890,32 @@ static CURLcode bearssl_sha256sum(const unsigned char *input,
 }
 
 const struct Curl_ssl Curl_ssl_bearssl = {
-  { CURLSSLBACKEND_BEARSSL, "bearssl" },
-  0,
+  { CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */
+  SSLSUPP_CAINFO_BLOB,
   sizeof(struct ssl_backend_data),
 
-  Curl_none_init,
-  Curl_none_cleanup,
-  bearssl_version,
-  Curl_none_check_cxn,
-  Curl_none_shutdown,
-  bearssl_data_pending,
-  bearssl_random,
-  Curl_none_cert_status_request,
-  bearssl_connect,
-  bearssl_connect_nonblocking,
-  Curl_ssl_getsock,
-  bearssl_get_internals,
-  bearssl_close,
-  Curl_none_close_all,
-  bearssl_session_free,
-  Curl_none_set_engine,
-  Curl_none_set_engine_default,
-  Curl_none_engines_list,
-  Curl_none_false_start,
-  bearssl_sha256sum
+  Curl_none_init,                  /* init */
+  Curl_none_cleanup,               /* cleanup */
+  bearssl_version,                 /* version */
+  Curl_none_check_cxn,             /* check_cxn */
+  Curl_none_shutdown,              /* shutdown */
+  bearssl_data_pending,            /* data_pending */
+  bearssl_random,                  /* random */
+  Curl_none_cert_status_request,   /* cert_status_request */
+  bearssl_connect,                 /* connect */
+  bearssl_connect_nonblocking,     /* connect_nonblocking */
+  Curl_ssl_getsock,                /* getsock */
+  bearssl_get_internals,           /* get_internals */
+  bearssl_close,                   /* close_one */
+  Curl_none_close_all,             /* close_all */
+  bearssl_session_free,            /* session_free */
+  Curl_none_set_engine,            /* set_engine */
+  Curl_none_set_engine_default,    /* set_engine_default */
+  Curl_none_engines_list,          /* engines_list */
+  Curl_none_false_start,           /* false_start */
+  bearssl_sha256sum,               /* sha256sum */
+  NULL,                            /* associate_connection */
+  NULL                             /* disassociate_connection */
 };
 
 #endif /* USE_BEARSSL */
index ca95376..e451f6a 100644 (file)
@@ -180,6 +180,7 @@ static bool is_separator(char c)
 static CURLcode gskit_status(struct Curl_easy *data, int rc,
                              const char *procname, CURLcode defcode)
 {
+  char buffer[STRERROR_LEN];
   /* Process GSKit status and map it to a CURLcode. */
   switch(rc) {
   case GSK_OK:
@@ -208,7 +209,8 @@ static CURLcode gskit_status(struct Curl_easy *data, int rc,
     case ENOMEM:
       return CURLE_OUT_OF_MEMORY;
     default:
-      failf(data, "%s I/O error: %s", procname, strerror(errno));
+      failf(data, "%s I/O error: %s", procname,
+            Curl_strerror(errno, buffer, sizeof(buffer)));
       break;
     }
     break;
@@ -223,13 +225,15 @@ static CURLcode gskit_status(struct Curl_easy *data, int rc,
 static CURLcode set_enum(struct Curl_easy *data, gsk_handle h,
                 GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok)
 {
+  char buffer[STRERROR_LEN];
   int rc = gsk_attribute_set_enum(h, id, value);
 
   switch(rc) {
   case GSK_OK:
     return CURLE_OK;
   case GSK_ERROR_IO:
-    failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno));
+    failf(data, "gsk_attribute_set_enum() I/O error: %s",
+          Curl_strerror(errno, buffer, sizeof(buffer)));
     break;
   case GSK_ATTRIBUTE_INVALID_ID:
     if(unsupported_ok)
@@ -245,13 +249,15 @@ static CURLcode set_enum(struct Curl_easy *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)
 {
+  char buffer[STRERROR_LEN];
   int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
 
   switch(rc) {
   case GSK_OK:
     return CURLE_OK;
   case GSK_ERROR_IO:
-    failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
+    failf(data, "gsk_attribute_set_buffer() I/O error: %s",
+          Curl_strerror(errno, buffer, sizeof(buffer)));
     break;
   case GSK_ATTRIBUTE_INVALID_ID:
     if(unsupported_ok)
@@ -267,6 +273,7 @@ static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h,
 static CURLcode set_numeric(struct Curl_easy *data,
                             gsk_handle h, GSK_NUM_ID id, int value)
 {
+  char buffer[STRERROR_LEN];
   int rc = gsk_attribute_set_numeric_value(h, id, value);
 
   switch(rc) {
@@ -274,7 +281,7 @@ static CURLcode set_numeric(struct Curl_easy *data,
     return CURLE_OK;
   case GSK_ERROR_IO:
     failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
-          strerror(errno));
+          Curl_strerror(errno, buffer, sizeof(buffer)));
     break;
   default:
     failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
@@ -287,13 +294,15 @@ static CURLcode set_numeric(struct Curl_easy *data,
 static CURLcode set_callback(struct Curl_easy *data,
                              gsk_handle h, GSK_CALLBACK_ID id, void *info)
 {
+  char buffer[STRERROR_LEN];
   int rc = gsk_attribute_set_callback(h, id, info);
 
   switch(rc) {
   case GSK_OK:
     return CURLE_OK;
   case GSK_ERROR_IO:
-    failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno));
+    failf(data, "gsk_attribute_set_callback() I/O error: %s",
+          Curl_strerror(errno, buffer, sizeof(buffer)));
     break;
   default:
     failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc));
@@ -966,7 +975,9 @@ static CURLcode gskit_connect_step2(struct Curl_easy *data,
         continue;       /* Retry. */
       }
       if(errno != ETIME) {
-        failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
+        char buffer[STRERROR_LEN];
+        failf(data, "QsoWaitForIOCompletion() I/O error: %s",
+              Curl_strerror(errno, buffer, sizeof(buffer)));
         cancel_async_handshake(conn, sockindex);
         close_async_handshake(connssl);
         return CURLE_SSL_CONNECT_ERROR;
@@ -1011,7 +1022,7 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data,
      CURLE_OK) {
     int i;
 
-    infof(data, "Server certificate:\n");
+    infof(data, "Server certificate:");
     p = cdev;
     for(i = 0; i++ < cdec; p++)
       switch(p->cert_data_id) {
@@ -1020,16 +1031,16 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data,
         certend = cert + cdev->cert_data_l;
         break;
       case CERT_DN_PRINTABLE:
-        infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
+        infof(data, "\t subject: %.*s", p->cert_data_l, p->cert_data_p);
         break;
       case CERT_ISSUER_DN_PRINTABLE:
-        infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
+        infof(data, "\t issuer: %.*s", p->cert_data_l, p->cert_data_p);
         break;
       case CERT_VALID_FROM:
-        infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
+        infof(data, "\t start date: %.*s", p->cert_data_l, p->cert_data_p);
         break;
       case CERT_VALID_TO:
-        infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
+        infof(data, "\t expire date: %.*s", p->cert_data_l, p->cert_data_p);
         break;
     }
   }
@@ -1192,6 +1203,7 @@ static int gskit_shutdown(struct Curl_easy *data,
   int what;
   int rc;
   char buf[120];
+  int loop = 10; /* don't get stuck */
 
   if(!BACKEND->handle)
     return 0;
@@ -1206,7 +1218,7 @@ static int gskit_shutdown(struct Curl_easy *data,
   what = SOCKET_READABLE(conn->sock[sockindex],
                          SSL_SHUTDOWN_TIMEOUT);
 
-  for(;;) {
+  while(loop--) {
     ssize_t nread;
 
     if(what < 0) {
@@ -1228,7 +1240,8 @@ static int gskit_shutdown(struct Curl_easy *data,
     nread = read(conn->sock[sockindex], buf, sizeof(buf));
 
     if(nread < 0) {
-      failf(data, "read: %s", strerror(errno));
+      char buffer[STRERROR_LEN];
+      failf(data, "read: %s", Curl_strerror(errno, buffer, sizeof(buffer)));
       rc = -1;
     }
 
index ecde5c4..1b145d8 100644 (file)
@@ -147,7 +147,7 @@ static void showtime(struct Curl_easy *data,
 
   msnprintf(str,
             sizeof(str),
-            "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
+            "  %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
             text,
             Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
             tm->tm_mday,
@@ -156,7 +156,7 @@ static void showtime(struct Curl_easy *data,
             tm->tm_hour,
             tm->tm_min,
             tm->tm_sec);
-  infof(data, "%s\n", str);
+  infof(data, "%s", str);
 }
 #endif
 
@@ -266,7 +266,7 @@ static CURLcode handshake(struct Curl_easy *data,
       if(!strerr)
         strerr = gnutls_strerror(rc);
 
-      infof(data, "gnutls_handshake() warning: %s\n", strerr);
+      infof(data, "gnutls_handshake() warning: %s", strerr);
       continue;
     }
     else if(rc < 0) {
@@ -330,6 +330,9 @@ set_ssl_version_min_max(struct Curl_easy *data,
       ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
     }
   }
+  else if(ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT) {
+    ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
+  }
 
   switch(ssl_version | ssl_version_max) {
   case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0:
@@ -338,11 +341,11 @@ set_ssl_version_min_max(struct Curl_easy *data,
     return CURLE_OK;
   case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1:
     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
-      "+VERS-TLS1.0:+VERS-TLS1.1";
+      "+VERS-TLS1.1:+VERS-TLS1.0";
     return CURLE_OK;
   case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2:
     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
-      "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2";
+      "+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0";
     return CURLE_OK;
   case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1:
     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
@@ -350,7 +353,7 @@ set_ssl_version_min_max(struct Curl_easy *data,
     return CURLE_OK;
   case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2:
     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
-      "+VERS-TLS1.1:+VERS-TLS1.2";
+      "+VERS-TLS1.2:+VERS-TLS1.1";
     return CURLE_OK;
   case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2:
     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
@@ -360,25 +363,16 @@ set_ssl_version_min_max(struct Curl_easy *data,
     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
       "+VERS-TLS1.3";
     return CURLE_OK;
-  case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT:
-    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
-      "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2"
-      ":+VERS-TLS1.3";
-    return CURLE_OK;
-  case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT:
-    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
-      "+VERS-TLS1.1:+VERS-TLS1.2"
-      ":+VERS-TLS1.3";
+  case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_3:
+    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0";
     return CURLE_OK;
-  case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT:
+  case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_3:
     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
-      "+VERS-TLS1.2"
-      ":+VERS-TLS1.3";
+      "+VERS-TLS1.3:+VERS-TLS1.2:+VERS-TLS1.1";
     return CURLE_OK;
-  case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT:
+  case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_3:
     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
-      "+VERS-TLS1.2"
-      ":+VERS-TLS1.3";
+      "+VERS-TLS1.3:+VERS-TLS1.2";
     return CURLE_OK;
   }
 
@@ -438,7 +432,7 @@ gtls_connect_step1(struct Curl_easy *data,
 
 #ifdef HAVE_GNUTLS_SRP
   if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
-    infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username));
+    infof(data, "Using TLS-SRP username: %s", SSL_SET_OPTION(username));
 
     rc = gnutls_srp_allocate_client_credentials(
            &backend->srp_client_cred);
@@ -468,7 +462,7 @@ gtls_connect_step1(struct Curl_easy *data,
                                                 SSL_CONN_CONFIG(CAfile),
                                                 GNUTLS_X509_FMT_PEM);
     if(rc < 0) {
-      infof(data, "error reading ca cert file %s (%s)\n",
+      infof(data, "error reading ca cert file %s (%s)",
             SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc));
       if(SSL_CONN_CONFIG(verifypeer)) {
         *certverifyresult = rc;
@@ -476,7 +470,7 @@ gtls_connect_step1(struct Curl_easy *data,
       }
     }
     else
-      infof(data, "found %d certificates in %s\n", rc,
+      infof(data, "found %d certificates in %s", rc,
             SSL_CONN_CONFIG(CAfile));
   }
 
@@ -486,7 +480,7 @@ gtls_connect_step1(struct Curl_easy *data,
                                                SSL_CONN_CONFIG(CApath),
                                                GNUTLS_X509_FMT_PEM);
     if(rc < 0) {
-      infof(data, "error reading ca cert file %s (%s)\n",
+      infof(data, "error reading ca cert file %s (%s)",
             SSL_CONN_CONFIG(CApath), gnutls_strerror(rc));
       if(SSL_CONN_CONFIG(verifypeer)) {
         *certverifyresult = rc;
@@ -494,7 +488,7 @@ gtls_connect_step1(struct Curl_easy *data,
       }
     }
     else
-      infof(data, "found %d certificates in %s\n",
+      infof(data, "found %d certificates in %s",
             rc, SSL_CONN_CONFIG(CApath));
   }
 
@@ -517,7 +511,7 @@ gtls_connect_step1(struct Curl_easy *data,
       return CURLE_SSL_CRL_BADFILE;
     }
     else
-      infof(data, "found %d CRL in %s\n",
+      infof(data, "found %d CRL in %s",
             rc, SSL_SET_OPTION(CRLfile));
   }
 
@@ -550,7 +544,7 @@ gtls_connect_step1(struct Curl_easy *data,
      (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname,
                              strlen(hostname)) < 0))
     infof(data, "WARNING: failed to configure server name indication (SNI) "
-          "TLS extension\n");
+          "TLS extension");
 
   /* Use default priorities */
   rc = gnutls_set_default_priority(session);
@@ -603,11 +597,12 @@ gtls_connect_step1(struct Curl_easy *data,
     free(prioritysrp);
 
     if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
-      infof(data, "This GnuTLS does not support SRP\n");
+      infof(data, "This GnuTLS does not support SRP");
     }
   }
   else {
 #endif
+    infof(data, "GnuTLS ciphers: %s", prioritylist);
     rc = gnutls_priority_set_direct(session, prioritylist, &err);
 #ifdef HAVE_GNUTLS_SRP
   }
@@ -632,14 +627,14 @@ gtls_connect_step1(struct Curl_easy *data,
       protocols[cur].data = (unsigned char *)ALPN_H2;
       protocols[cur].size = ALPN_H2_LENGTH;
       cur++;
-      infof(data, "ALPN, offering %.*s\n", ALPN_H2_LENGTH, ALPN_H2);
+      infof(data, "ALPN, offering %.*s", ALPN_H2_LENGTH, ALPN_H2);
     }
 #endif
 
     protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
     protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
     cur++;
-    infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+    infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
 
     gnutls_alpn_set_protocols(session, protocols, cur, 0);
   }
@@ -745,7 +740,7 @@ gtls_connect_step1(struct Curl_easy *data,
       gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
 
       /* Informational message */
-      infof(data, "SSL re-using session ID\n");
+      infof(data, "SSL re-using session ID");
     }
     Curl_ssl_sessionid_unlock(data);
   }
@@ -848,7 +843,7 @@ gtls_connect_step3(struct Curl_easy *data,
                                      gnutls_cipher_get(session),
                                      gnutls_mac_get(session));
 
-  infof(data, "SSL connection using %s / %s\n",
+  infof(data, "SSL connection using %s / %s",
         gnutls_protocol_get_name(version), ptr);
 
   /* This function will return the peer's raw certificate (chain) as sent by
@@ -861,7 +856,7 @@ gtls_connect_step3(struct Curl_easy *data,
   if(!chainp) {
     if(SSL_CONN_CONFIG(verifypeer) ||
        SSL_CONN_CONFIG(verifyhost) ||
-       SSL_SET_OPTION(issuercert)) {
+       SSL_CONN_CONFIG(issuercert)) {
 #ifdef HAVE_GNUTLS_SRP
       if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
          && SSL_SET_OPTION(username) != NULL
@@ -879,7 +874,7 @@ gtls_connect_step3(struct Curl_easy *data,
       }
 #endif
     }
-    infof(data, "\t common name: WARNING couldn't obtain\n");
+    infof(data, " common name: WARNING couldn't obtain");
   }
 
   if(data->set.ssl.certinfo && chainp) {
@@ -926,13 +921,13 @@ gtls_connect_step3(struct Curl_easy *data,
         return CURLE_PEER_FAILED_VERIFICATION;
       }
       else
-        infof(data, "\t server certificate verification FAILED\n");
+        infof(data, "  server certificate verification FAILED");
     }
     else
-      infof(data, "\t server certificate verification OK\n");
+      infof(data, "  server certificate verification OK");
   }
   else
-    infof(data, "\t server certificate verification SKIPPED\n");
+    infof(data, "  server certificate verification SKIPPED");
 
   if(SSL_CONN_CONFIG(verifystatus)) {
     if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
@@ -944,7 +939,7 @@ gtls_connect_step3(struct Curl_easy *data,
 
       rc = gnutls_ocsp_status_request_get(session, &status_request);
 
-      infof(data, "\t server certificate status verification FAILED\n");
+      infof(data, " server certificate status verification FAILED");
 
       if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
         failf(data, "No OCSP response received");
@@ -1032,10 +1027,10 @@ gtls_connect_step3(struct Curl_easy *data,
       return CURLE_SSL_INVALIDCERTSTATUS;
     }
     else
-      infof(data, "\t server certificate status verification OK\n");
+      infof(data, "  server certificate status verification OK");
   }
   else
-    infof(data, "\t server certificate status verification SKIPPED\n");
+    infof(data, "  server certificate status verification SKIPPED");
 
   /* initialize an X.509 certificate structure. */
   gnutls_x509_crt_init(&x509_cert);
@@ -1045,21 +1040,21 @@ gtls_connect_step3(struct Curl_easy *data,
        gnutls_x509_crt_t format */
     gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
 
-  if(SSL_SET_OPTION(issuercert)) {
+  if(SSL_CONN_CONFIG(issuercert)) {
     gnutls_x509_crt_init(&x509_issuer);
-    issuerp = load_file(SSL_SET_OPTION(issuercert));
+    issuerp = load_file(SSL_CONN_CONFIG(issuercert));
     gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
     rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
     gnutls_x509_crt_deinit(x509_issuer);
     unload_file(issuerp);
     if(rc <= 0) {
       failf(data, "server certificate issuer check failed (IssuerCert: %s)",
-            SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
+            SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none");
       gnutls_x509_crt_deinit(x509_cert);
       return CURLE_SSL_ISSUER_ERROR;
     }
-    infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n",
-          SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
+    infof(data, "  server certificate issuer check OK (Issuer Cert: %s)",
+          SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none");
   }
 
   size = sizeof(certname);
@@ -1069,7 +1064,7 @@ gtls_connect_step3(struct Curl_easy *data,
                                      certname,
                                      &size);
   if(rc) {
-    infof(data, "error fetching CN from cert:%s\n",
+    infof(data, "error fetching CN from cert:%s",
           gnutls_strerror(rc));
   }
 
@@ -1129,11 +1124,11 @@ gtls_connect_step3(struct Curl_easy *data,
       return CURLE_PEER_FAILED_VERIFICATION;
     }
     else
-      infof(data, "\t common name: %s (does not match '%s')\n",
+      infof(data, "  common name: %s (does not match '%s')",
             certname, SSL_HOST_DISPNAME());
   }
   else
-    infof(data, "\t common name: %s (matched)\n", certname);
+    infof(data, "  common name: %s (matched)", certname);
 
   /* Check for time-based validity */
   certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
@@ -1146,7 +1141,7 @@ gtls_connect_step3(struct Curl_easy *data,
       return CURLE_SSL_CONNECT_ERROR;
     }
     else
-      infof(data, "\t server certificate expiration date verify FAILED\n");
+      infof(data, "  server certificate expiration date verify FAILED");
   }
   else {
     if(certclock < time(NULL)) {
@@ -1157,10 +1152,10 @@ gtls_connect_step3(struct Curl_easy *data,
         return CURLE_PEER_FAILED_VERIFICATION;
       }
       else
-        infof(data, "\t server certificate expiration date FAILED\n");
+        infof(data, "  server certificate expiration date FAILED");
     }
     else
-      infof(data, "\t server certificate expiration date OK\n");
+      infof(data, "  server certificate expiration date OK");
   }
 
   certclock = gnutls_x509_crt_get_activation_time(x509_cert);
@@ -1173,7 +1168,7 @@ gtls_connect_step3(struct Curl_easy *data,
       return CURLE_SSL_CONNECT_ERROR;
     }
     else
-      infof(data, "\t server certificate activation date verify FAILED\n");
+      infof(data, "  server certificate activation date verify FAILED");
   }
   else {
     if(certclock > time(NULL)) {
@@ -1184,10 +1179,10 @@ gtls_connect_step3(struct Curl_easy *data,
         return CURLE_PEER_FAILED_VERIFICATION;
       }
       else
-        infof(data, "\t server certificate activation date FAILED\n");
+        infof(data, "  server certificate activation date FAILED");
     }
     else
-      infof(data, "\t server certificate activation date OK\n");
+      infof(data, "  server certificate activation date OK");
   }
 
   ptr = SSL_PINNED_PUB_KEY();
@@ -1213,19 +1208,19 @@ gtls_connect_step3(struct Curl_easy *data,
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   /* public key algorithm's parameters */
   algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
-  infof(data, "\t certificate public key: %s\n",
+  infof(data, "  certificate public key: %s",
         gnutls_pk_algorithm_get_name(algo));
 
   /* version of the X.509 certificate. */
-  infof(data, "\t certificate version: #%d\n",
+  infof(data, "  certificate version: #%d",
         gnutls_x509_crt_get_version(x509_cert));
 
 
   rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields);
   if(rc)
-    infof(data, "Failed to get certificate name\n");
+    infof(data, "Failed to get certificate name");
   else {
-    infof(data, "\t subject: %s\n", certfields.data);
+    infof(data, "  subject: %s", certfields.data);
 
     certclock = gnutls_x509_crt_get_activation_time(x509_cert);
     showtime(data, "start date", certclock);
@@ -1238,9 +1233,9 @@ gtls_connect_step3(struct Curl_easy *data,
 
   rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields);
   if(rc)
-    infof(data, "Failed to get certificate issuer\n");
+    infof(data, "Failed to get certificate issuer");
   else {
-    infof(data, "\t issuer: %s\n", certfields.data);
+    infof(data, "  issuer: %s", certfields.data);
 
     gnutls_free(certfields.data);
   }
@@ -1251,7 +1246,7 @@ gtls_connect_step3(struct Curl_easy *data,
   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,
+      infof(data, "ALPN, server accepted to use %.*s", proto.size,
           proto.data);
 
 #ifdef USE_HTTP2
@@ -1268,7 +1263,7 @@ gtls_connect_step3(struct Curl_easy *data,
       }
     }
     else
-      infof(data, "ALPN, server did not agree to a protocol\n");
+      infof(data, "ALPN, server did not agree to a protocol");
 
     Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
@@ -1438,6 +1433,10 @@ static void close_one(struct ssl_connect_data *connssl)
 {
   struct ssl_backend_data *backend = connssl->backend;
   if(backend->session) {
+    char buf[32];
+    /* Maybe the server has already sent a close notify alert.
+       Read it to avoid an RST on the TCP connection. */
+    (void)gnutls_record_recv(backend->session, buf, sizeof(buf));
     gnutls_bye(backend->session, GNUTLS_SHUT_WR);
     gnutls_deinit(backend->session);
     backend->session = NULL;
@@ -1506,7 +1505,7 @@ static int gtls_shutdown(struct Curl_easy *data, struct connectdata *conn,
           break;
         case GNUTLS_E_AGAIN:
         case GNUTLS_E_INTERRUPTED:
-          infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
+          infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED");
           break;
         default:
           retval = -1;
@@ -1620,7 +1619,7 @@ static bool gtls_cert_status_request(void)
 }
 
 static void *gtls_get_internals(struct ssl_connect_data *connssl,
-                                     CURLINFO info UNUSED_PARAM)
+                                CURLINFO info UNUSED_PARAM)
 {
   struct ssl_backend_data *backend = connssl->backend;
   (void)info;
index 3a0be0f..780d13e 100644 (file)
@@ -41,7 +41,9 @@
 #include <mbedtls/net.h>
 #endif
 #include <mbedtls/ssl.h>
+#if MBEDTLS_VERSION_NUMBER < 0x03000000
 #include <mbedtls/certs.h>
+#endif
 #include <mbedtls/x509.h>
 
 #include <mbedtls/error.h>
@@ -89,6 +91,10 @@ struct ssl_backend_data {
 #define THREADING_SUPPORT
 #endif
 
+#ifndef MBEDTLS_ERROR_C
+#define mbedtls_strerror(a,b,c) b[0] = 0
+#endif
+
 #if defined(THREADING_SUPPORT)
 static mbedtls_entropy_context ts_entropy;
 
@@ -179,6 +185,17 @@ static Curl_send mbed_send;
 
 static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
 {
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+  switch(version) {
+    case CURL_SSLVERSION_TLSv1_0:
+    case CURL_SSLVERSION_TLSv1_1:
+    case CURL_SSLVERSION_TLSv1_2:
+      *mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
+      return CURLE_OK;
+    case CURL_SSLVERSION_TLSv1_3:
+      break;
+  }
+#else
   switch(version) {
     case CURL_SSLVERSION_TLSv1_0:
       *mbedver = MBEDTLS_SSL_MINOR_VERSION_1;
@@ -192,6 +209,8 @@ static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
     case CURL_SSLVERSION_TLSv1_3:
       break;
   }
+#endif
+
   return CURLE_SSL_CONNECT_ERROR;
 }
 
@@ -201,8 +220,13 @@ set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+  int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3;
+  int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3;
+#else
   int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
   int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1;
+#endif
   long ssl_version = SSL_CONN_CONFIG(version);
   long ssl_version_max = SSL_CONN_CONFIG(version_max);
   CURLcode result = CURLE_OK;
@@ -250,12 +274,14 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
   const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
   const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
   char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
+  const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
   const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
   const char * const hostname = SSL_HOST_NAME();
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
   const long int port = SSL_HOST_PORT();
+#endif
   int ret = -1;
   char errorbuf[128];
-  errorbuf[0] = 0;
 
   if((SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) ||
      (SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)) {
@@ -270,9 +296,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
   ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex,
                               &ts_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",
           -ret, errorbuf);
   }
@@ -283,9 +307,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
   ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, mbedtls_entropy_func,
                               &backend->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",
           -ret, errorbuf);
   }
@@ -298,9 +320,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
     ret = mbedtls_x509_crt_parse_file(&backend->cacert, 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",
             ssl_cafile, -ret, errorbuf);
 
@@ -313,9 +333,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
     ret = mbedtls_x509_crt_parse_path(&backend->cacert, 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",
             ssl_capath, -ret, errorbuf);
 
@@ -331,9 +349,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
     ret = mbedtls_x509_crt_parse_file(&backend->clicert, ssl_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",
             ssl_cert, -ret, errorbuf);
 
@@ -341,27 +357,72 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
     }
   }
 
-  /* Load the client private key */
-  mbedtls_pk_init(&backend->pk);
-
-  if(SSL_SET_OPTION(key)) {
-    ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key),
-                                   SSL_SET_OPTION(key_passwd));
-    if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) ||
-                     mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY)))
-      ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
+  if(ssl_cert_blob) {
+    const unsigned char *blob_data =
+      (const unsigned char *)ssl_cert_blob->data;
+    ret = mbedtls_x509_crt_parse(&backend->clicert, blob_data,
+                                 ssl_cert_blob->len);
 
     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",
             SSL_SET_OPTION(key), -ret, errorbuf);
-
       return CURLE_SSL_CERTPROBLEM;
     }
   }
 
+  /* Load the client private key */
+  mbedtls_pk_init(&backend->pk);
+
+  if(SSL_SET_OPTION(key) || SSL_SET_OPTION(key_blob)) {
+    if(SSL_SET_OPTION(key)) {
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+      ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key),
+                                     SSL_SET_OPTION(key_passwd),
+                                     mbedtls_ctr_drbg_random,
+                                     &backend->ctr_drbg);
+#else
+      ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key),
+                                     SSL_SET_OPTION(key_passwd));
+#endif
+
+      if(ret) {
+        mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+        failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
+              SSL_SET_OPTION(key), -ret, errorbuf);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+    }
+    else {
+      const struct curl_blob *ssl_key_blob = SSL_SET_OPTION(key_blob);
+      const unsigned char *key_data =
+        (const unsigned char *)ssl_key_blob->data;
+      const char *passwd = SSL_SET_OPTION(key_passwd);
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+      ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len,
+                                 (const unsigned char *)passwd,
+                                 passwd ? strlen(passwd) : 0,
+                                 mbedtls_ctr_drbg_random,
+                                 &backend->ctr_drbg);
+#else
+      ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len,
+                                 (const unsigned char *)passwd,
+                                 passwd ? strlen(passwd) : 0);
+#endif
+
+      if(ret) {
+        mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+        failf(data, "Error parsing private key - mbedTLS: (-0x%04X) %s",
+              -ret, errorbuf);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+    }
+
+    if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) ||
+                     mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY)))
+      ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
+  }
+
   /* Load the CRL */
   mbedtls_x509_crl_init(&backend->crl);
 
@@ -369,9 +430,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
     ret = mbedtls_x509_crl_parse_file(&backend->crl, 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",
             ssl_crlfile, -ret, errorbuf);
 
@@ -379,7 +438,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
     }
   }
 
-  infof(data, "mbedTLS: Connecting to %s:%ld\n", hostname, port);
+  infof(data, "mbedTLS: Connecting to %s:%ld", hostname, port);
 
   mbedtls_ssl_config_init(&backend->config);
 
@@ -404,10 +463,12 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
   switch(SSL_CONN_CONFIG(version)) {
   case CURL_SSLVERSION_DEFAULT:
   case CURL_SSLVERSION_TLSv1:
+#if MBEDTLS_VERSION_NUMBER < 0x03000000
     mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
                                  MBEDTLS_SSL_MINOR_VERSION_1);
-    infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n");
+    infof(data, "mbedTLS: Set min SSL version to TLS 1.0");
     break;
+#endif
   case CURL_SSLVERSION_TLSv1_0:
   case CURL_SSLVERSION_TLSv1_1:
   case CURL_SSLVERSION_TLSv1_2:
@@ -459,7 +520,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
         failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
         return CURLE_SSL_CONNECT_ERROR;
       }
-      infof(data, "mbedTLS re-using session\n");
+      infof(data, "mbedTLS re-using session");
     }
     Curl_ssl_sessionid_unlock(data);
   }
@@ -468,7 +529,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
                             &backend->cacert,
                             &backend->crl);
 
-  if(SSL_SET_OPTION(key)) {
+  if(SSL_SET_OPTION(key) || SSL_SET_OPTION(key_blob)) {
     mbedtls_ssl_conf_own_cert(&backend->config,
                               &backend->clicert, &backend->pk);
   }
@@ -497,7 +558,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
       return CURLE_SSL_CONNECT_ERROR;
     }
     for(p = &backend->protocols[0]; *p; ++p)
-      infof(data, "ALPN, offering %s\n", *p);
+      infof(data, "ALPN, offering %s", *p);
   }
 #endif
 
@@ -553,18 +614,14 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
   }
   else if(ret) {
     char errorbuf[128];
-    errorbuf[0] = 0;
-#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(&backend->ssl)
-    );
+  infof(data, "mbedTLS: Handshake complete, cipher is %s",
+        mbedtls_ssl_get_ciphersuite(&backend->ssl));
 
   ret = mbedtls_ssl_get_verify_result(&backend->ssl);
 
@@ -601,9 +658,9 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
       return CURLE_OUT_OF_MEMORY;
 
     if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0)
-      infof(data, "Dumping cert info:\n%s\n", buffer);
+      infof(data, "Dumping cert info: %s", buffer);
     else
-      infof(data, "Unable to dump certificate information.\n");
+      infof(data, "Unable to dump certificate information");
 
     free(buffer);
   }
@@ -611,10 +668,15 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
   if(pinnedpubkey) {
     int size;
     CURLcode result;
-    mbedtls_x509_crt *p;
-    unsigned char pubkey[PUB_DER_MAX_BYTES];
+    mbedtls_x509_crt *p = NULL;
+    unsigned char *pubkey = NULL;
 
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+    if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) ||
+       !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) {
+#else
     if(!peercert || !peercert->raw.p || !peercert->raw.len) {
+#endif
       failf(data, "Failed due to missing peer certificate");
       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
     }
@@ -624,39 +686,54 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
     if(!p)
       return CURLE_OUT_OF_MEMORY;
 
+    pubkey = malloc(PUB_DER_MAX_BYTES);
+
+    if(!pubkey) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto pinnedpubkey_error;
+    }
+
     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_VERSION_NUMBER >= 0x03000000
+    if(mbedtls_x509_crt_parse_der(p,
+                        peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p),
+                        peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) {
+#else
     if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
+#endif
       failf(data, "Failed copying peer certificate");
-      mbedtls_x509_crt_free(p);
-      free(p);
-      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+      result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+      goto pinnedpubkey_error;
     }
 
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+    size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey,
+                                       PUB_DER_MAX_BYTES);
+#else
     size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
+#endif
 
     if(size <= 0) {
       failf(data, "Failed copying public key from peer certificate");
-      mbedtls_x509_crt_free(p);
-      free(p);
-      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+      result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+      goto pinnedpubkey_error;
     }
 
     /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */
     result = Curl_pin_peer_pubkey(data,
                                   pinnedpubkey,
                                   &pubkey[PUB_DER_MAX_BYTES - size], size);
+    pinnedpubkey_error:
+    mbedtls_x509_crt_free(p);
+    free(p);
+    free(pubkey);
     if(result) {
-      mbedtls_x509_crt_free(p);
-      free(p);
       return result;
     }
-
-    mbedtls_x509_crt_free(p);
-    free(p);
   }
 
 #ifdef HAS_ALPN
@@ -664,7 +741,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
     const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&backend->ssl);
 
     if(next_protocol) {
-      infof(data, "ALPN, server accepted to use %s\n", next_protocol);
+      infof(data, "ALPN, server accepted to use %s", next_protocol);
 #ifdef USE_NGHTTP2
       if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID,
                   NGHTTP2_PROTO_VERSION_ID_LEN) &&
@@ -679,7 +756,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
         }
     }
     else {
-      infof(data, "ALPN, server did not agree to a protocol\n");
+      infof(data, "ALPN, server did not agree to a protocol");
     }
     Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
@@ -687,7 +764,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
 #endif
 
   connssl->connecting_state = ssl_connect_3;
-  infof(data, "SSL connected\n");
+  infof(data, "SSL connected");
 
   return CURLE_OK;
 }
@@ -775,8 +852,13 @@ static void mbedtls_close(struct Curl_easy *data,
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
-
+  char buf[32];
   (void) data;
+
+  /* Maybe the server has already sent a close notify alert.
+     Read it to avoid an RST on the TCP connection. */
+  (void)mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, sizeof(buf));
+
   mbedtls_pk_free(&backend->pk);
   mbedtls_x509_crt_free(&backend->clicert);
   mbedtls_x509_crt_free(&backend->cacert);
@@ -844,15 +926,12 @@ static CURLcode mbedtls_random(struct Curl_easy *data,
   mbedtls_ctr_drbg_context ctr_drbg;
   mbedtls_entropy_init(&ctr_entropy);
   mbedtls_ctr_drbg_init(&ctr_drbg);
-  errorbuf[0] = 0;
 
   ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
                               &ctr_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_seed returned (-0x%04X) %s",
           -ret, errorbuf);
   }
@@ -860,9 +939,7 @@ static CURLcode mbedtls_random(struct Curl_easy *data,
     ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length);
 
     if(ret) {
-#ifdef MBEDTLS_ERROR_C
       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* MBEDTLS_ERROR_C */
       failf(data, "mbedTLS: ctr_drbg_init returned (-0x%04X) %s",
             -ret, errorbuf);
     }
@@ -1046,12 +1123,17 @@ static CURLcode mbedtls_sha256sum(const unsigned char *input,
                                   unsigned char *sha256sum,
                                   size_t sha256len UNUSED_PARAM)
 {
+  /* TODO: explain this for different mbedtls 2.x vs 3 version */
   (void)sha256len;
 #if MBEDTLS_VERSION_NUMBER < 0x02070000
   mbedtls_sha256(input, inputlen, sha256sum, 0);
 #else
   /* returns 0 on success, otherwise failure */
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+  if(mbedtls_sha256(input, inputlen, sha256sum, 0) != 0)
+#else
   if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0)
+#endif
     return CURLE_BAD_FUNCTION_ARGUMENT;
 #endif
   return CURLE_OK;
index 473f517..751755c 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2013 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2013 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
  *
  * This software is licensed as described in the file COPYING, which
@@ -55,10 +55,8 @@ int Curl_mbedtlsthreadlock_thread_setup(void)
     return 0;     /* error, no number of threads defined */
 
   for(i = 0;  i < NUMT;  i++) {
-    int ret;
 #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
-    ret = pthread_mutex_init(&mutex_buf[i], NULL);
-    if(ret)
+    if(pthread_mutex_init(&mutex_buf[i], NULL))
       return 0; /* pthread_mutex_init failed */
 #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
     mutex_buf[i] = CreateMutex(0, FALSE, 0);
@@ -78,14 +76,11 @@ int Curl_mbedtlsthreadlock_thread_cleanup(void)
     return 0; /* error, no threads locks defined */
 
   for(i = 0; i < NUMT; i++) {
-    int ret;
 #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
-    ret = pthread_mutex_destroy(&mutex_buf[i]);
-    if(ret)
+    if(pthread_mutex_destroy(&mutex_buf[i]))
       return 0; /* pthread_mutex_destroy failed */
 #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
-    ret = CloseHandle(mutex_buf[i]);
-    if(!ret)
+    if(!CloseHandle(mutex_buf[i]))
       return 0; /* CloseHandle failed */
 #endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
   }
@@ -98,17 +93,14 @@ int Curl_mbedtlsthreadlock_thread_cleanup(void)
 int Curl_mbedtlsthreadlock_lock_function(int n)
 {
   if(n < NUMT) {
-    int ret;
 #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
-    ret = pthread_mutex_lock(&mutex_buf[n]);
-    if(ret) {
+    if(pthread_mutex_lock(&mutex_buf[n])) {
       DEBUGF(fprintf(stderr,
                      "Error: mbedtlsthreadlock_lock_function failed\n"));
       return 0; /* pthread_mutex_lock failed */
     }
 #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
-    ret = (WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED?1:0);
-    if(ret) {
+    if(WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED) {
       DEBUGF(fprintf(stderr,
                      "Error: mbedtlsthreadlock_lock_function failed\n"));
       return 0; /* pthread_mutex_lock failed */
@@ -121,17 +113,14 @@ int Curl_mbedtlsthreadlock_lock_function(int n)
 int Curl_mbedtlsthreadlock_unlock_function(int n)
 {
   if(n < NUMT) {
-    int ret;
 #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
-    ret = pthread_mutex_unlock(&mutex_buf[n]);
-    if(ret) {
+    if(pthread_mutex_unlock(&mutex_buf[n])) {
       DEBUGF(fprintf(stderr,
                      "Error: mbedtlsthreadlock_unlock_function failed\n"));
       return 0; /* pthread_mutex_unlock failed */
     }
 #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
-    ret = ReleaseMutex(mutex_buf[n]);
-    if(!ret) {
+    if(!ReleaseMutex(mutex_buf[n])) {
       DEBUGF(fprintf(stderr,
                      "Error: mbedtlsthreadlock_unlock_function failed\n"));
       return 0; /* pthread_mutex_lock failed */
index bf8600d..3db9184 100644 (file)
@@ -167,14 +167,14 @@ mesalink_connect_step1(struct Curl_easy *data,
       }
       infof(data,
           "error setting certificate verify locations,"
-          " continuing anyway:\n");
+          " continuing anyway:");
     }
     else {
-      infof(data, "successfully set certificate verify locations:\n");
+      infof(data, "successfully set certificate verify locations:");
     }
-    infof(data, " CAfile: %s\n",
+    infof(data, " CAfile: %s",
           SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): "none");
-    infof(data, " CApath: %s\n",
+    infof(data, " CApath: %s",
           SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath): "none");
   }
 
@@ -196,7 +196,7 @@ mesalink_connect_step1(struct Curl_easy *data,
       return CURLE_SSL_CONNECT_ERROR;
     }
     infof(data,
-          "client cert: %s\n",
+          "client cert: %s",
           SSL_CONN_CONFIG(clientcert)?
           SSL_CONN_CONFIG(clientcert): "none");
   }
@@ -209,7 +209,7 @@ mesalink_connect_step1(struct Curl_easy *data,
       return CURLE_SSL_CIPHER;
     }
 #endif
-    infof(data, "Cipher selection: %s\n", ciphers);
+    infof(data, "Cipher selection: %s", ciphers);
   }
 
   if(BACKEND->handle)
@@ -273,7 +273,7 @@ mesalink_connect_step1(struct Curl_easy *data,
         return CURLE_SSL_CONNECT_ERROR;
       }
       /* Informational message */
-      infof(data, "SSL re-using session ID\n");
+      infof(data, "SSL re-using session ID");
     }
     Curl_ssl_sessionid_unlock(data);
   }
@@ -326,7 +326,7 @@ mesalink_connect_step2(struct Curl_easy *data,
 
   connssl->connecting_state = ssl_connect_3;
   infof(data,
-        "SSL connection using %s / %s\n",
+        "SSL connection using %s / %s",
         SSL_get_version(BACKEND->handle),
         SSL_get_cipher_name(BACKEND->handle));
 
@@ -356,7 +356,7 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex)
                               sockindex));
     if(incache) {
       if(old_ssl_sessionid != our_ssl_sessionid) {
-        infof(data, "old SSL session ID is stale, removing\n");
+        infof(data, "old SSL session ID is stale, removing");
         Curl_ssl_delsessionid(data, old_ssl_sessionid);
         incache = FALSE;
       }
index 1582b1e..cf65789 100644 (file)
@@ -433,7 +433,7 @@ static char *dup_nickname(struct Curl_easy *data, const char *str)
   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);
+          "please use \"./%s\" to force file name", str, str);
     return strdup(str);
   }
 
@@ -824,7 +824,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
 #endif
 
   if(!SSL_CONN_CONFIG(verifypeer)) {
-    infof(data, "skipping SSL peer certificate verification\n");
+    infof(data, "skipping SSL peer certificate verification");
     return SECSuccess;
   }
 
@@ -857,15 +857,15 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
 #endif
     case SSL_NEXT_PROTO_NO_SUPPORT:
     case SSL_NEXT_PROTO_NO_OVERLAP:
-      infof(data, "ALPN/NPN, server did not agree to a protocol\n");
+      infof(data, "ALPN/NPN, server did not agree to a protocol");
       return;
 #ifdef SSL_ENABLE_ALPN
     case SSL_NEXT_PROTO_SELECTED:
-      infof(data, "ALPN, server accepted to use %.*s\n", buflen, buf);
+      infof(data, "ALPN, server accepted to use %.*s", buflen, buf);
       break;
 #endif
     case SSL_NEXT_PROTO_NEGOTIATED:
-      infof(data, "NPN, server accepted to use %.*s\n", buflen, buf);
+      infof(data, "NPN, server accepted to use %.*s", buflen, buf);
       break;
     }
 
@@ -937,7 +937,7 @@ static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data,
 
   *canFalseStart = PR_TRUE;
 
-  infof(data, "Trying TLS False Start\n");
+  infof(data, "Trying TLS False Start");
 
 end:
   return SECSuccess;
@@ -955,17 +955,17 @@ static void display_cert_info(struct Curl_easy *data,
   subject = CERT_NameToAscii(&cert->subject);
   issuer = CERT_NameToAscii(&cert->issuer);
   common_name = CERT_GetCommonName(&cert->subject);
-  infof(data, "\tsubject: %s\n", subject);
+  infof(data, "subject: %s\n", subject);
 
   CERT_GetCertTimes(cert, &notBefore, &notAfter);
   PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
   PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
-  infof(data, "\tstart date: %s\n", timeString);
+  infof(data, " start date: %s", timeString);
   PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
   PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
-  infof(data, "\texpire date: %s\n", timeString);
-  infof(data, "\tcommon name: %s\n", common_name);
-  infof(data, "\tissuer: %s\n", issuer);
+  infof(data, " expire date: %s", timeString);
+  infof(data, " common name: %s", common_name);
+  infof(data, " issuer: %s", issuer);
 
   PR_Free(subject);
   PR_Free(issuer);
@@ -987,13 +987,13 @@ static CURLcode display_conn_info(struct Curl_easy *data, PRFileDesc *sock)
      channel.cipherSuite) {
     if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
                               &suite, sizeof(suite)) == SECSuccess) {
-      infof(data, "SSL connection using %s\n", suite.cipherSuiteName);
+      infof(data, "SSL connection using %s", suite.cipherSuiteName);
     }
   }
 
   cert = SSL_PeerCertificate(sock);
   if(cert) {
-    infof(data, "Server certificate:\n");
+    infof(data, "Server certificate:");
 
     if(!data->set.ssl.certinfo) {
       display_cert_info(data, cert);
@@ -1058,7 +1058,7 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
   /* print only info about the cert, the error is printed off the callback */
   cert = SSL_PeerCertificate(sock);
   if(cert) {
-    infof(data, "Server certificate:\n");
+    infof(data, "Server certificate:");
     display_cert_info(data, cert);
     CERT_DestroyCertificate(cert);
   }
@@ -1132,7 +1132,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
   /* report the resulting status */
   switch(result) {
   case CURLE_OK:
-    infof(data, "pinned public key verified successfully!\n");
+    infof(data, "pinned public key verified successfully!");
     break;
   case CURLE_SSL_PINNEDPUBKEYNOTMATCH:
     failf(data, "failed to verify pinned public key");
@@ -1196,7 +1196,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
       return SECFailure;
     }
 
-    infof(data, "NSS: client certificate from file\n");
+    infof(data, "NSS: client certificate from file");
     display_cert_info(data, cert);
 
     *pRetCert = cert;
@@ -1234,7 +1234,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
     return SECFailure;
   }
 
-  infof(data, "NSS: using client certificate: %s\n", nickname);
+  infof(data, "NSS: using client certificate: %s", nickname);
   display_cert_info(data, *pRetCert);
   return SECSuccess;
 }
@@ -1355,7 +1355,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
     if(!certpath)
       return CURLE_OUT_OF_MEMORY;
 
-    infof(data, "Initializing NSS with certpath: %s\n", certpath);
+    infof(data, "Initializing NSS with certpath: %s", certpath);
     nss_context = NSS_InitContext(certpath, "", "", "", &initparams,
                                   NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
     free(certpath);
@@ -1365,10 +1365,10 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
 
     err = PR_GetError();
     err_name = nss_error_to_name(err);
-    infof(data, "Unable to initialize NSS database: %d (%s)\n", err, err_name);
+    infof(data, "Unable to initialize NSS database: %d (%s)", err, err_name);
   }
 
-  infof(data, "Initializing NSS with certpath: none\n");
+  infof(data, "Initializing NSS with certpath: none");
   nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY
          | NSS_INIT_NOCERTDB   | NSS_INIT_NOMODDB       | NSS_INIT_FORCEOPEN
          | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
@@ -1546,6 +1546,14 @@ static void close_one(struct ssl_connect_data *connssl)
   const bool client_cert = (backend->client_nickname != NULL)
     || (backend->obj_clicert != NULL);
 
+  if(backend->handle) {
+    char buf[32];
+    /* Maybe the server has already sent a close notify alert.
+       Read it to avoid an RST on the TCP connection. */
+    (void)PR_Recv(backend->handle, buf, (int)sizeof(buf), 0,
+                  PR_INTERVAL_NO_WAIT);
+  }
+
   free(backend->client_nickname);
   backend->client_nickname = NULL;
 
@@ -1650,8 +1658,8 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
   if(capath && !capath[0])
     capath = NULL;
 
-  infof(data, " CAfile: %s\n", cafile ? cafile : "none");
-  infof(data, " CApath: %s\n", capath ? capath : "none");
+  infof(data, " CAfile: %s", cafile ? cafile : "none");
+  infof(data, " CApath: %s", capath ? capath : "none");
 
   /* load libnssckbi.so if no other trust roots were specified */
   use_trust_module = !cafile && !capath;
@@ -1660,7 +1668,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
   if(use_trust_module && !trust_module) {
     /* libnssckbi.so needed but not yet loaded --> load it! */
     result = nss_load_module(&trust_module, trust_library, "trust");
-    infof(data, "%s %s\n", (result) ? "failed to load" : "loaded",
+    infof(data, "%s %s", (result) ? "failed to load" : "loaded",
           trust_library);
     if(result == CURLE_FAILED_INIT)
       /* If libnssckbi.so is not available (or fails to load), one can still
@@ -1669,7 +1677,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
   }
   else if(!use_trust_module && trust_module) {
     /* libnssckbi.so not needed but already loaded --> unload it! */
-    infof(data, "unloading %s\n", trust_library);
+    infof(data, "unloading %s", trust_library);
     nss_unload_module(&trust_module);
   }
   PR_Unlock(nss_trustload_lock);
@@ -1702,7 +1710,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
         if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
           /* This is purposefully tolerant of errors so non-PEM files can
            * be in the same directory */
-          infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
+          infof(data, "failed to load '%s' from CURLOPT_CAPATH", fullpath);
 
         free(fullpath);
       }
@@ -1710,7 +1718,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
       PR_CloseDir(dir);
     }
     else
-      infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
+      infof(data, "warning: CURLOPT_CAPATH not a directory (%s)", capath);
   }
 
   return CURLE_OK;
@@ -1813,7 +1821,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
       curlerr = CURLE_SSL_CERTPROBLEM;
 
     /* print the error number and error string */
-    infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err));
+    infof(data, "NSS error %d (%s)", err, nss_error_to_name(err));
 
     /* print a human-readable message describing the error if available */
     nss_print_error_message(data, err);
@@ -1887,7 +1895,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
   PR_Unlock(nss_initlock);
   if(result == CURLE_FAILED_INIT)
     infof(data, "WARNING: failed to load NSS PEM library %s. Using "
-                "OpenSSL PEM certificates will not work.\n", pem_library);
+                "OpenSSL PEM certificates will not work.", pem_library);
   else if(result)
     goto error;
 
@@ -1922,8 +1930,8 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
     sslver_req_str = nss_sslver_to_name(sslver.max);
     sslver_supp_str = nss_sslver_to_name(sslver_supported.max);
     if(sslver_req_str && sslver_supp_str)
-      infof(data, "Falling back from %s to max supported SSL version (%s)\n",
-                  sslver_req_str, sslver_supp_str);
+      infof(data, "Falling back from %s to max supported SSL version (%s)",
+            sslver_req_str, sslver_supp_str);
     free(sslver_req_str);
     free(sslver_supp_str);
     sslver.max = sslver_supported.max;
@@ -1936,11 +1944,11 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
   /* unless the user explicitly asks to allow the protocol vulnerability, we
      use the work-around */
   if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess)
-    infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n",
+    infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d",
           ssl_cbc_random_iv);
 #else
   if(ssl_cbc_random_iv)
-    infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n");
+    infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in");
 #endif
 
   if(SSL_CONN_CONFIG(cipher_list)) {
@@ -1951,7 +1959,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
   }
 
   if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost))
-    infof(data, "warning: ignoring value of ssl.verifyhost\n");
+    infof(data, "warning: ignoring value of ssl.verifyhost");
 
   /* bypass the default SSL_AuthCertificate() hook in case we do not want to
    * verify peer */
@@ -1971,7 +1979,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
     const CURLcode rv = nss_load_ca_certificates(data, conn, sockindex);
     if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer))
       /* not a fatal error because we are not going to verify the peer */
-      infof(data, "warning: CA certificates failed to load\n");
+      infof(data, "warning: CA certificates failed to load");
     else if(rv) {
       result = rv;
       goto error;
@@ -1984,7 +1992,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
       result = rv;
       goto error;
     }
-    infof(data, "  CRLfile: %s\n", SSL_SET_OPTION(CRLfile));
+    infof(data, "  CRLfile: %s", SSL_SET_OPTION(CRLfile));
   }
 
   if(SSL_SET_OPTION(primary.clientcert)) {
@@ -2179,9 +2187,9 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
   if(result)
     goto error;
 
-  if(SSL_SET_OPTION(issuercert)) {
+  if(SSL_CONN_CONFIG(issuercert)) {
     SECStatus ret = SECFailure;
-    char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert));
+    char *nickname = dup_nickname(data, SSL_CONN_CONFIG(issuercert));
     if(nickname) {
       /* we support only nicknames in case of issuercert for now */
       ret = check_issuer_cert(backend->handle, nickname);
@@ -2189,12 +2197,12 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
     }
 
     if(SECFailure == ret) {
-      infof(data, "SSL certificate issuer check failed\n");
+      infof(data, "SSL certificate issuer check failed");
       result = CURLE_SSL_ISSUER_ERROR;
       goto error;
     }
     else {
-      infof(data, "SSL certificate issuer check ok\n");
+      infof(data, "SSL certificate issuer check ok");
     }
   }
 
@@ -2306,7 +2314,7 @@ static ssize_t nss_send(struct Curl_easy *data,    /* transfer */
     else {
       /* print the error number and error string */
       const char *err_name = nss_error_to_name(err);
-      infof(data, "SSL write: error %d (%s)\n", err, err_name);
+      infof(data, "SSL write: error %d (%s)", err, err_name);
 
       /* print a human-readable message describing the error if available */
       nss_print_error_message(data, err);
@@ -2348,7 +2356,7 @@ static ssize_t nss_recv(struct Curl_easy *data,    /* transfer */
     else {
       /* print the error number and error string */
       const char *err_name = nss_error_to_name(err);
-      infof(data, "SSL read: errno %d (%s)\n", err, err_name);
+      infof(data, "SSL read: errno %d (%s)", err, err_name);
 
       /* print a human-readable message describing the error if available */
       nss_print_error_message(data, err);
@@ -2427,7 +2435,7 @@ static bool nss_false_start(void)
 }
 
 static void *nss_get_internals(struct ssl_connect_data *connssl,
-                                    CURLINFO info UNUSED_PARAM)
+                               CURLINFO info UNUSED_PARAM)
 {
   struct ssl_backend_data *backend = connssl->backend;
   (void)info;
index ebd7abc..87f4b02 100644 (file)
      !defined(OPENSSL_IS_BORINGSSL))
 #define HAVE_SSL_CTX_SET_CIPHERSUITES
 #define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
-/* SET_EC_CURVES available under the same preconditions: see
+/* SET_EC_CURVES is available under the same preconditions: see
  * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html
  */
 #define HAVE_SSL_CTX_SET_EC_CURVES
 #endif
 
 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
-/* up2date versions of OpenSSL maintain the default reasonably secure without
- * breaking compatibility, so it is better not to override the default by curl
+/* up2date versions of OpenSSL maintain reasonably secure defaults without
+ * breaking compatibility, so it is better not to override the defaults in curl
  */
 #define DEFAULT_CIPHER_SELECTION NULL
 #else
@@ -435,17 +435,16 @@ static bool rand_enough(void)
 
 static CURLcode ossl_seed(struct Curl_easy *data)
 {
-  /* we have the "SSL is seeded" boolean static to prevent multiple
-     time-consuming seedings in vain */
-  static bool ssl_seeded = FALSE;
   char fname[256];
 
-  if(ssl_seeded)
+  /* This might get called before it has been added to a multi handle */
+  if(data->multi && data->multi->ssl_seeded)
     return CURLE_OK;
 
   if(rand_enough()) {
     /* OpenSSL 1.1.0+ will return here */
-    ssl_seeded = TRUE;
+    if(data->multi)
+      data->multi->ssl_seeded = TRUE;
     return CURLE_OK;
   }
 
@@ -518,7 +517,7 @@ static CURLcode ossl_seed(struct Curl_easy *data)
       return CURLE_OK;
   }
 
-  infof(data, "libcurl is now using a weak random seed!\n");
+  infof(data, "libcurl is now using a weak random seed!");
   return (rand_enough() ? CURLE_OK :
     CURLE_SSL_CONNECT_ERROR /* confusing error code */);
 }
@@ -1193,7 +1192,7 @@ static int ossl_init(void)
                          CONF_MFLAGS_IGNORE_MISSING_FILE);
 #endif
 
-  /* Lets get nice error messages */
+  /* Let's get nice error messages */
   SSL_load_error_strings();
 
   /* Init the global ciphers and digests */
@@ -1354,7 +1353,7 @@ static CURLcode ossl_set_engine_default(struct Curl_easy *data)
 #ifdef USE_OPENSSL_ENGINE
   if(data->state.engine) {
     if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) {
-      infof(data, "set default crypto engine '%s'\n",
+      infof(data, "set default crypto engine '%s'",
             ENGINE_get_id(data->state.engine));
     }
     else {
@@ -1400,7 +1399,13 @@ static void ossl_closeone(struct Curl_easy *data,
 {
   struct ssl_backend_data *backend = connssl->backend;
   if(backend->handle) {
+    char buf[32];
     set_logger(conn, data);
+
+    /* Maybe the server has already sent a close notify alert.
+       Read it to avoid an RST on the TCP connection. */
+    (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
+
     (void)SSL_shutdown(backend->handle);
     SSL_set_connect_state(backend->handle);
 
@@ -1442,6 +1447,7 @@ static int ossl_shutdown(struct Curl_easy *data,
   int err;
   bool done = FALSE;
   struct ssl_backend_data *backend = connssl->backend;
+  int loop = 10;
 
 #ifndef CURL_DISABLE_FTP
   /* This has only been tested on the proftpd server, and the mod_tls code
@@ -1455,7 +1461,7 @@ static int ossl_shutdown(struct Curl_easy *data,
 
   if(backend->handle) {
     buffsize = (int)sizeof(buf);
-    while(!done) {
+    while(!done && loop--) {
       int what = SOCKET_READABLE(conn->sock[sockindex],
                                  SSL_SHUTDOWN_TIMEOUT);
       if(what > 0) {
@@ -1475,11 +1481,11 @@ static int ossl_shutdown(struct Curl_easy *data,
           break;
         case SSL_ERROR_WANT_READ:
           /* there's data pending, re-invoke SSL_read() */
-          infof(data, "SSL_ERROR_WANT_READ\n");
+          infof(data, "SSL_ERROR_WANT_READ");
           break;
         case SSL_ERROR_WANT_WRITE:
           /* SSL wants a write. Really odd. Let's bail out. */
-          infof(data, "SSL_ERROR_WANT_WRITE\n");
+          infof(data, "SSL_ERROR_WANT_WRITE");
           done = TRUE;
           break;
         default:
@@ -1511,14 +1517,14 @@ static int ossl_shutdown(struct Curl_easy *data,
 #ifdef HAVE_SSL_GET_SHUTDOWN
       switch(SSL_get_shutdown(backend->handle)) {
       case SSL_SENT_SHUTDOWN:
-        infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n");
+        infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN");
         break;
       case SSL_RECEIVED_SHUTDOWN:
-        infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n");
+        infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN");
         break;
       case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
         infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
-              "SSL_RECEIVED__SHUTDOWN\n");
+              "SSL_RECEIVED__SHUTDOWN");
         break;
       }
 #endif
@@ -1585,7 +1591,7 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
       if(Curl_cert_hostcheck(match_pattern2, hostname)) {
         res = TRUE;
         infof(data,
-                " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
+                " subjectAltName: host \"%s\" matched cert's \"%s\"",
                 dispname, match_pattern2);
       }
     }
@@ -1604,7 +1610,7 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
   (void)data;
 #endif
   if(Curl_cert_hostcheck(match_pattern, hostname)) {
-    infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
+    infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"",
                   dispname, match_pattern);
     return TRUE;
   }
@@ -1724,7 +1730,7 @@ static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn,
           if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) {
             ipmatched = TRUE;
             infof(data,
-                  " subjectAltName: host \"%s\" matched cert's IP address!\n",
+                  " subjectAltName: host \"%s\" matched cert's IP address!",
                   dispname);
           }
           break;
@@ -1741,7 +1747,7 @@ static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn,
     /* an alternative name matched */
     ;
   else if(dNSName || iPAddress) {
-    infof(data, " subjectAltName does not match %s\n", dispname);
+    infof(data, " subjectAltName does not match %s", dispname);
     failf(data, "SSL: no alternative certificate subject name matches "
           "target host name '%s'", dispname);
     result = CURLE_PEER_FAILED_VERIFICATION;
@@ -1763,7 +1769,7 @@ static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn,
 
     /* we have the name entry and we will now convert this to a string
        that we can use for comparison. Doing this we support BMPstring,
-       UTF8 etc. */
+       UTF8, etc. */
 
     if(i >= 0) {
       ASN1_STRING *tmp =
@@ -1823,7 +1829,7 @@ static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn,
       result = CURLE_PEER_FAILED_VERIFICATION;
     }
     else {
-      infof(data, " common name: %s (matched)\n", peer_CN);
+      infof(data, " common name: %s (matched)", peer_CN);
     }
     if(peer_CN)
       OPENSSL_free(peer_CN);
@@ -1959,7 +1965,7 @@ static CURLcode verifystatus(struct Curl_easy *data,
     goto end;
   }
 
-  infof(data, "SSL certificate status: %s (%d)\n",
+  infof(data, "SSL certificate status: %s (%d)",
         OCSP_cert_status_str(cert_status), cert_status);
 
   switch(cert_status) {
@@ -2054,6 +2060,10 @@ static const char *ssl_msg_type(int ssl_ver, int msg)
       case SSL3_MT_ENCRYPTED_EXTENSIONS:
         return "Encrypted Extensions";
 #endif
+#ifdef SSL3_MT_SUPPLEMENTAL_DATA
+      case SSL3_MT_SUPPLEMENTAL_DATA:
+        return "Supplemental data";
+#endif
 #ifdef SSL3_MT_END_OF_EARLY_DATA
       case SSL3_MT_END_OF_EARLY_DATA:
         return "End of early data";
@@ -2152,7 +2162,7 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
 
   /* Log progress for interesting records only (like Handshake or Alert), skip
    * all raw record headers (content_type == SSL3_RT_HEADER or ssl_ver == 0).
-   * For TLS 1.3, skip notification of the decrypted inner Content Type.
+   * For TLS 1.3, skip notification of the decrypted inner Content-Type.
    */
   if(ssl_ver
 #ifdef SSL3_RT_INNER_CONTENT_TYPE
@@ -2263,7 +2273,7 @@ select_next_proto_cb(SSL *ssl,
 #ifdef USE_HTTP2
   if(data->state.httpwant >= CURL_HTTP_VERSION_2 &&
      !select_next_protocol(out, outlen, in, inlen, ALPN_H2, ALPN_H2_LENGTH)) {
-    infof(data, "NPN, negotiated HTTP2 (%s)\n", ALPN_H2);
+    infof(data, "NPN, negotiated HTTP2 (%s)", ALPN_H2);
     conn->negnpn = CURL_HTTP_VERSION_2;
     return SSL_TLSEXT_ERR_OK;
   }
@@ -2271,12 +2281,12 @@ select_next_proto_cb(SSL *ssl,
 
   if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1,
                            ALPN_HTTP_1_1_LENGTH)) {
-    infof(data, "NPN, negotiated HTTP1.1\n");
+    infof(data, "NPN, negotiated HTTP1.1");
     conn->negnpn = CURL_HTTP_VERSION_1_1;
     return SSL_TLSEXT_ERR_OK;
   }
 
-  infof(data, "NPN, no overlap, use HTTP1.1\n");
+  infof(data, "NPN, no overlap, use HTTP1.1");
   *out = (unsigned char *)ALPN_HTTP_1_1;
   *outlen = ALPN_HTTP_1_1_LENGTH;
   conn->negnpn = CURL_HTTP_VERSION_1_1;
@@ -2293,7 +2303,7 @@ set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn)
   long curl_ssl_version_min = SSL_CONN_CONFIG(version);
   long curl_ssl_version_max;
 
-  /* convert cURL min SSL version option to OpenSSL constant */
+  /* convert curl min SSL version option to OpenSSL constant */
 #if defined(OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER)
   uint16_t ossl_ssl_version_min = 0;
   uint16_t ossl_ssl_version_max = 0;
@@ -2323,7 +2333,7 @@ set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn)
      We don't want to pass 0 to SSL_CTX_set_min_proto_version as
      it would enable all versions down to the lowest supported by
      the library.
-     So we skip this, and stay with the OS default
+     So we skip this, and stay with the library default
   */
   if(curl_ssl_version_min != CURL_SSLVERSION_DEFAULT) {
     if(!SSL_CTX_set_min_proto_version(ctx, ossl_ssl_version_min)) {
@@ -2334,7 +2344,7 @@ set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn)
   /* ... then, TLS max version */
   curl_ssl_version_max = SSL_CONN_CONFIG(version_max);
 
-  /* convert cURL max SSL version option to OpenSSL constant */
+  /* convert curl max SSL version option to OpenSSL constant */
   switch(curl_ssl_version_max) {
     case CURL_SSLVERSION_MAX_TLSv1_0:
       ossl_ssl_version_max = TLS1_VERSION;
@@ -2493,7 +2503,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
                                         &old_ssl_sessionid, NULL, sockindex));
     if(incache) {
       if(old_ssl_sessionid != ssl_sessionid) {
-        infof(data, "old SSL session ID is stale, removing\n");
+        infof(data, "old SSL session ID is stale, removing");
         Curl_ssl_delsessionid(data, old_ssl_sessionid);
         incache = FALSE;
       }
@@ -2517,7 +2527,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
 static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
                                         const struct curl_blob *ca_info_blob)
 {
-  /* these need freed at the end */
+  /* these need to be freed at the end */
   BIO *cbio = NULL;
   STACK_OF(X509_INFO) *inf = NULL;
 
@@ -2652,8 +2662,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
     return CURLE_SSL_CONNECT_ERROR;
   }
 
-  if(backend->ctx)
-    SSL_CTX_free(backend->ctx);
+  DEBUGASSERT(!backend->ctx);
   backend->ctx = SSL_CTX_new(req_method);
 
   if(!backend->ctx) {
@@ -2675,23 +2684,23 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
   }
 #endif
 
-  /* OpenSSL contains code to work-around lots of bugs and flaws in various
+  /* OpenSSL contains code to work around lots of bugs and flaws in various
      SSL-implementations. SSL_CTX_set_options() is used to enabled those
      work-arounds. The man page for this option states that SSL_OP_ALL enables
      all the work-arounds and that "It is usually safe to use SSL_OP_ALL to
      enable the bug workaround options if compatibility with somewhat broken
      implementations is desired."
 
-     The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to
+     The "-no_ticket" option was introduced in OpenSSL 0.9.8j. It's a flag to
      disable "rfc4507bis session ticket support".  rfc4507bis was later turned
      into the proper RFC5077 it seems: https://tools.ietf.org/html/rfc5077
 
      The enabled extension concerns the session management. I wonder how often
-     libcurl stops a connection and then resumes a TLS session. also, sending
-     the session data is some overhead. .I suggest that you just use your
+     libcurl stops a connection and then resumes a TLS session. Also, sending
+     the session data is some overhead. I suggest that you just use your
      proposed patch (which explicitly disables TICKET).
 
-     If someone writes an application with libcurl and openssl who wants to
+     If someone writes an application with libcurl and OpenSSL who wants to
      enable the feature, one can do this in the SSL callback.
 
      SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper
@@ -2727,7 +2736,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
 #endif
 
 #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
-  /* unless the user explicitly ask to allow the protocol vulnerability we
+  /* unless the user explicitly asks to allow the protocol vulnerability we
      use the work-around */
   if(!SSL_SET_OPTION(enable_beast))
     ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
@@ -2787,14 +2796,14 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
 
       memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH);
       cur += ALPN_H2_LENGTH;
-      infof(data, "ALPN, offering %s\n", ALPN_H2);
+      infof(data, "ALPN, offering %s", ALPN_H2);
     }
 #endif
 
     protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
     memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
     cur += ALPN_HTTP_1_1_LENGTH;
-    infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+    infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
 
     /* expects length prefixed preference ordered list of protocols in wire
      * format
@@ -2826,7 +2835,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
       failf(data, "failed setting cipher list: %s", ciphers);
       return CURLE_SSL_CIPHER;
     }
-    infof(data, "Cipher selection: %s\n", ciphers);
+    infof(data, "Cipher selection: %s", ciphers);
   }
 
 #ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
@@ -2837,7 +2846,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
         failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13);
         return CURLE_SSL_CIPHER;
       }
-      infof(data, "TLS 1.3 cipher selection: %s\n", ciphers13);
+      infof(data, "TLS 1.3 cipher selection: %s", ciphers13);
     }
   }
 #endif
@@ -2863,7 +2872,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
   if(ssl_authtype == CURL_TLSAUTH_SRP) {
     char * const ssl_username = SSL_SET_OPTION(username);
 
-    infof(data, "Using TLS-SRP username: %s\n", ssl_username);
+    infof(data, "Using TLS-SRP username: %s", ssl_username);
 
     if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) {
       failf(data, "Unable to set SRP user name");
@@ -2874,7 +2883,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
       return CURLE_BAD_FUNCTION_ARGUMENT;
     }
     if(!SSL_CONN_CONFIG(cipher_list)) {
-      infof(data, "Setting cipher list SRP\n");
+      infof(data, "Setting cipher list SRP");
 
       if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) {
         failf(data, "failed setting SRP cipher list");
@@ -2927,7 +2936,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
                                NULL, cert_name, sizeof(cert_name))) {
           strcpy(cert_name, "Unknown");
         }
-        infof(data, "SSL: Checking cert \"%s\"\n", cert_name);
+        infof(data, "SSL: Checking cert %s\"\n", cert_name);
 #endif
 
         encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
@@ -3009,7 +3018,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
            OpenSSL. */
         if(X509_STORE_add_cert(store, x509) == 1) {
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-          infof(data, "SSL: Imported cert \"%s\"\n", cert_name);
+          infof(data, "SSL: Imported cert \"%s\"", cert_name);
 #endif
           imported_native_ca = true;
         }
@@ -3024,9 +3033,9 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
         return result;
     }
     if(imported_native_ca)
-      infof(data, "successfully imported windows ca store\n");
+      infof(data, "successfully imported Windows CA store");
     else
-      infof(data, "error importing windows ca store, continuing anyway\n");
+      infof(data, "error importing Windows CA store, continuing anyway");
   }
 #endif
 
@@ -3038,8 +3047,8 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
         failf(data, "error importing CA certificate blob");
         return result;
       }
-      /* Only warning if no certificate verification is required. */
-      infof(data, "error importing CA certificate blob, continuing anyway\n");
+      /* Only warn if no certificate verification is required. */
+      infof(data, "error importing CA certificate blob, continuing anyway");
     }
   }
 
@@ -3053,10 +3062,10 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
           failf(data, "error setting certificate file: %s", ssl_cafile);
           return CURLE_SSL_CACERT_BADFILE;
         }
-        /* Continue with a warning if no certificate verif is required. */
-        infof(data, "error setting certificate file, continuing anyway\n");
+        /* Continue with warning if certificate verification isn't required. */
+        infof(data, "error setting certificate file, continuing anyway");
       }
-      infof(data, " CAfile: %s\n", ssl_cafile);
+      infof(data, " CAfile: %s", ssl_cafile);
     }
     if(ssl_capath) {
       if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) {
@@ -3065,16 +3074,16 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
           failf(data, "error setting certificate path: %s", ssl_capath);
           return CURLE_SSL_CACERT_BADFILE;
         }
-        /* Continue with a warning if no certificate verif is required. */
-        infof(data, "error setting certificate path, continuing anyway\n");
+        /* Continue with warning if certificate verification isn't required. */
+        infof(data, "error setting certificate path, continuing anyway");
       }
-      infof(data, " CApath: %s\n", ssl_capath);
+      infof(data, " CApath: %s", ssl_capath);
     }
   }
 #else
   if(ssl_cafile || ssl_capath) {
     /* tell SSL where to find CA certificates that are used to verify
-       the servers certificate. */
+       the server's certificate. */
     if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) {
       if(verifypeer && !imported_native_ca) {
         /* Fail if we insist on successfully verifying the server. */
@@ -3087,14 +3096,14 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
       /* Just continue with a warning if no strict certificate verification
          is required. */
       infof(data, "error setting certificate verify locations,"
-            " continuing anyway:\n");
+            " continuing anyway:");
     }
     else {
       /* Everything is fine. */
-      infof(data, "successfully set certificate verify locations:\n");
+      infof(data, "successfully set certificate verify locations:");
     }
-    infof(data, " CAfile: %s\n", ssl_cafile ? ssl_cafile : "none");
-    infof(data, " CApath: %s\n", ssl_capath ? ssl_capath : "none");
+    infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
+    infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
   }
 #endif
 
@@ -3102,13 +3111,13 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
   if(verifypeer &&
      !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) {
     /* verifying the peer without any CA certificates won't
-       work so use openssl's built in default as fallback */
+       work so use openssl's built-in default as fallback */
     SSL_CTX_set_default_verify_paths(backend->ctx);
   }
 #endif
 
   if(ssl_crlfile) {
-    /* tell SSL where to find CRL file that is used to check certificate
+    /* tell OpenSSL where to find CRL file that is used to check certificate
      * revocation */
     lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(backend->ctx),
                                  X509_LOOKUP_file());
@@ -3118,11 +3127,11 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
       return CURLE_SSL_CRL_BADFILE;
     }
     /* Everything is fine. */
-    infof(data, "successfully load CRL file:\n");
+    infof(data, "successfully loaded CRL file:");
     X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx),
                          X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
 
-    infof(data, "  CRLfile: %s\n", ssl_crlfile);
+    infof(data, "  CRLfile: %s", ssl_crlfile);
   }
 
   if(verifypeer) {
@@ -3144,7 +3153,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
          only, instead of needing the whole chain.
 
          Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we
-         cannot do partial chains with CRL check.
+         cannot do partial chains with CRL check.
       */
       X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx),
                            X509_V_FLAG_PARTIAL_CHAIN);
@@ -3152,7 +3161,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
 #endif
   }
 
-  /* SSL always tries to verify the peer, this only says whether it should
+  /* OpenSSL always tries to verify the peer, this only says whether it should
    * fail to connect if the verification fails, or if it should continue
    * anyway. In the latter case the result of the verification is checked with
    * SSL_get_verify_result() below. */
@@ -3167,7 +3176,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
 #endif
 
   /* Enable the session cache because it's a prerequisite for the "new session"
-   * callback. Use the "external storage" mode to avoid that OpenSSL creates
+   * callback. Use the "external storage" mode to prevent OpenSSL from creating
    * an internal session cache.
    */
   SSL_CTX_set_session_cache_mode(backend->ctx,
@@ -3186,7 +3195,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
     }
   }
 
-  /* Lets make an SSL structure */
+  /* Let's make an SSL structure */
   if(backend->handle)
     SSL_free(backend->handle);
   backend->handle = SSL_new(backend->ctx);
@@ -3226,7 +3235,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
     data->state.buffer[nlen] = 0;
     if(!SSL_set_tlsext_host_name(backend->handle, data->state.buffer))
       infof(data, "WARNING: failed to configure server name indication (SNI) "
-            "TLS extension\n");
+            "TLS extension");
   }
 #endif
 
@@ -3244,7 +3253,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
       return CURLE_SSL_CONNECT_ERROR;
     }
     /* Informational message */
-    infof(data, "SSL re-using session ID\n");
+    infof(data, "SSL re-using session ID");
   }
   Curl_ssl_sessionid_unlock(data);
 
@@ -3326,7 +3335,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
       /* 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
+      /* Get the earliest error code from the thread's error queue and remove
          the entry. */
       errdetail = ERR_get_error();
 
@@ -3355,7 +3364,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
     !defined(LIBRESSL_VERSION_NUMBER) && \
     !defined(OPENSSL_IS_BORINGSSL))
       /* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on
-         OpenSSL version above v1.1.1, not Libre SSL nor BoringSSL */
+         OpenSSL version above v1.1.1, not LibreSSL nor BoringSSL */
       else if((lib == ERR_LIB_SSL) &&
               (reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)) {
           /* If client certificate is required, communicate the
@@ -3372,7 +3381,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
       /* detail is already set to the SSL error above */
 
       /* If we e.g. use SSLv2 request-method and the server doesn't like us
-       * (RST connection etc.), OpenSSL gives no explanation whatsoever and
+       * (RST connection, etc.), OpenSSL gives no explanation whatsoever and
        * the SO_ERROR is also lost.
        */
       if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
@@ -3395,11 +3404,11 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
     }
   }
   else {
-    /* we have been connected fine, we're not waiting for anything else. */
+    /* we connected fine, we're not waiting for anything else. */
     connssl->connecting_state = ssl_connect_3;
 
     /* Informational message */
-    infof(data, "SSL connection using %s / %s\n",
+    infof(data, "SSL connection using %s / %s",
           SSL_get_version(backend->handle),
           SSL_get_cipher(backend->handle));
 
@@ -3412,7 +3421,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
       unsigned int len;
       SSL_get0_alpn_selected(backend->handle, &neg_protocol, &len);
       if(len) {
-        infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol);
+        infof(data, "ALPN, server accepted to use %.*s", len, neg_protocol);
 
 #ifdef USE_HTTP2
         if(len == ALPN_H2_LENGTH &&
@@ -3427,7 +3436,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
         }
       }
       else
-        infof(data, "ALPN, server did not agree to a protocol\n");
+        infof(data, "ALPN, server did not agree to a protocol");
 
       Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                           BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
@@ -3637,7 +3646,7 @@ static CURLcode get_cert_chain(struct Curl_easy *data,
 
     pubkey = X509_get_pubkey(x);
     if(!pubkey)
-      infof(data, "   Unable to load public key\n");
+      infof(data, "   Unable to load public key");
     else {
       int pktype;
 #ifdef HAVE_OPAQUE_EVP_PKEY
@@ -3814,7 +3823,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
 }
 
 /*
- * Get the server cert, verify it and show it etc, only call failf() if the
+ * Get the server cert, verify it and show it, etc., only call failf() if the
  * 'strict' argument is TRUE as otherwise all this is for informational
  * purposes only!
  *
@@ -3851,23 +3860,23 @@ static CURLcode servercert(struct Curl_easy *data,
     return CURLE_PEER_FAILED_VERIFICATION;
   }
 
-  infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server");
+  infof(data, "%s certificate:", SSL_IS_PROXY() ? "Proxy" : "Server");
 
   rc = x509_name_oneline(X509_get_subject_name(backend->server_cert),
                          buffer, sizeof(buffer));
-  infof(data, " subject: %s\n", rc?"[NONE]":buffer);
+  infof(data, " subject: %s", rc?"[NONE]":buffer);
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   {
     long len;
     ASN1_TIME_print(mem, X509_get0_notBefore(backend->server_cert));
     len = BIO_get_mem_data(mem, (char **) &ptr);
-    infof(data, " start date: %.*s\n", len, ptr);
+    infof(data, " start date: %.*s", (int)len, ptr);
     (void)BIO_reset(mem);
 
     ASN1_TIME_print(mem, X509_get0_notAfter(backend->server_cert));
     len = BIO_get_mem_data(mem, (char **) &ptr);
-    infof(data, " expire date: %.*s\n", len, ptr);
+    infof(data, " expire date: %.*s", (int)len, ptr);
     (void)BIO_reset(mem);
   }
 #endif
@@ -3891,16 +3900,16 @@ static CURLcode servercert(struct Curl_easy *data,
     result = CURLE_PEER_FAILED_VERIFICATION;
   }
   else {
-    infof(data, " issuer: %s\n", buffer);
+    infof(data, " issuer: %s", buffer);
 
     /* We could do all sorts of certificate verification stuff here before
        deallocating the certificate. */
 
     /* e.g. match issuer name with provided issuer certificate */
-    if(SSL_SET_OPTION(issuercert) || SSL_SET_OPTION(issuercert_blob)) {
-      if(SSL_SET_OPTION(issuercert_blob))
-        fp = BIO_new_mem_buf(SSL_SET_OPTION(issuercert_blob)->data,
-                             (int)SSL_SET_OPTION(issuercert_blob)->len);
+    if(SSL_CONN_CONFIG(issuercert) || SSL_CONN_CONFIG(issuercert_blob)) {
+      if(SSL_CONN_CONFIG(issuercert_blob))
+        fp = BIO_new_mem_buf(SSL_CONN_CONFIG(issuercert_blob)->data,
+                             (int)SSL_CONN_CONFIG(issuercert_blob)->len);
       else {
         fp = BIO_new(BIO_s_file());
         if(!fp) {
@@ -3914,10 +3923,10 @@ static CURLcode servercert(struct Curl_easy *data,
           return CURLE_OUT_OF_MEMORY;
         }
 
-        if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) {
+        if(BIO_read_filename(fp, SSL_CONN_CONFIG(issuercert)) <= 0) {
           if(strict)
             failf(data, "SSL: Unable to open issuer cert (%s)",
-                  SSL_SET_OPTION(issuercert));
+                  SSL_CONN_CONFIG(issuercert));
           BIO_free(fp);
           X509_free(backend->server_cert);
           backend->server_cert = NULL;
@@ -3929,7 +3938,7 @@ static CURLcode servercert(struct Curl_easy *data,
       if(!issuer) {
         if(strict)
           failf(data, "SSL: Unable to read issuer cert (%s)",
-                SSL_SET_OPTION(issuercert));
+                SSL_CONN_CONFIG(issuercert));
         BIO_free(fp);
         X509_free(issuer);
         X509_free(backend->server_cert);
@@ -3940,7 +3949,7 @@ static CURLcode servercert(struct Curl_easy *data,
       if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) {
         if(strict)
           failf(data, "SSL: Certificate issuer check failed (%s)",
-                SSL_SET_OPTION(issuercert));
+                SSL_CONN_CONFIG(issuercert));
         BIO_free(fp);
         X509_free(issuer);
         X509_free(backend->server_cert);
@@ -3948,8 +3957,8 @@ static CURLcode servercert(struct Curl_easy *data,
         return CURLE_SSL_ISSUER_ERROR;
       }
 
-      infof(data, " SSL certificate issuer check ok (%s)\n",
-            SSL_SET_OPTION(issuercert));
+      infof(data, " SSL certificate issuer check ok (%s)",
+            SSL_CONN_CONFIG(issuercert));
       BIO_free(fp);
       X509_free(issuer);
     }
@@ -3967,11 +3976,11 @@ static CURLcode servercert(struct Curl_easy *data,
       }
       else
         infof(data, " SSL certificate verify result: %s (%ld),"
-              " continuing anyway.\n",
+              " continuing anyway.",
               X509_verify_cert_error_string(lerr), lerr);
     }
     else
-      infof(data, " SSL certificate verify ok.\n");
+      infof(data, " SSL certificate verify ok.");
   }
 
 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
@@ -4015,7 +4024,7 @@ static CURLcode ossl_connect_step3(struct Curl_easy *data,
   /*
    * We check certificates to authenticate the server; otherwise we risk
    * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to
-   * verify the peer ignore faults and failures from the server cert
+   * verify the peer, ignore faults and failures from the server cert
    * operations.
    */
 
@@ -4053,7 +4062,7 @@ static CURLcode ossl_connect_common(struct Curl_easy *data,
     const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
 
     if(timeout_ms < 0) {
-      /* no need to continue if time already is up */
+      /* no need to continue if time is already up */
       failf(data, "SSL connection timeout");
       return CURLE_OPERATION_TIMEDOUT;
     }
@@ -4244,7 +4253,7 @@ static ssize_t ossl_send(struct Curl_easy *data,
 #endif
         ) {
         char ver[120];
-        ossl_version(ver, 120);
+        (void)ossl_version(ver, sizeof(ver));
         failf(data, "Error: %s does not support double SSL tunneling.", ver);
       }
       else
@@ -4534,9 +4543,6 @@ static void ossl_disassociate_connection(struct Curl_easy *data,
     return;
 
   if(SSL_SET_OPTION(primary.sessionid)) {
-    bool isproxy = FALSE;
-    bool incache;
-    void *old_ssl_sessionid = NULL;
     int data_idx = ossl_get_ssl_data_index();
     int connectdata_idx = ossl_get_ssl_conn_index();
     int sockindex_idx = ossl_get_ssl_sockindex_index();
@@ -4544,9 +4550,6 @@ static void ossl_disassociate_connection(struct Curl_easy *data,
 
     if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0 &&
        proxy_idx >= 0) {
-      /* Invalidate the session cache entry, if any */
-      isproxy = SSL_get_ex_data(backend->handle, proxy_idx) ? TRUE : FALSE;
-
       /* Disable references to data in "new session" callback to avoid
        * accessing a stale pointer. */
       SSL_set_ex_data(backend->handle, data_idx, NULL);
@@ -4554,13 +4557,6 @@ static void ossl_disassociate_connection(struct Curl_easy *data,
       SSL_set_ex_data(backend->handle, sockindex_idx, NULL);
       SSL_set_ex_data(backend->handle, proxy_idx, NULL);
     }
-
-    Curl_ssl_sessionid_lock(data);
-    incache = !(Curl_ssl_getsessionid(data, conn, isproxy,
-                                      &old_ssl_sessionid, NULL, sockindex));
-    if(incache)
-      Curl_ssl_delsessionid(data, old_ssl_sessionid);
-    Curl_ssl_sessionid_unlock(data);
   }
 }
 
index d5247f9..2ac97ce 100644 (file)
@@ -34,7 +34,7 @@
 #include "sendf.h"
 #include "vtls.h"
 #include "select.h"
-
+#include "strerror.h"
 #include "multiif.h"
 
 struct ssl_backend_data
@@ -73,7 +73,7 @@ cr_connect(struct Curl_easy *data UNUSED_PARAM,
                     struct connectdata *conn UNUSED_PARAM,
                     int sockindex UNUSED_PARAM)
 {
-  infof(data, "rustls_connect: unimplemented\n");
+  infof(data, "rustls_connect: unimplemented");
   return CURLE_SSL_CONNECT_ERROR;
 }
 
@@ -129,10 +129,12 @@ cr_recv(struct Curl_easy *data, int sockindex,
   io_error = rustls_connection_read_tls(rconn, read_cb,
     &conn->sock[sockindex], &tls_bytes_read);
   if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
-    infof(data, "sread: EAGAIN or EWOULDBLOCK\n");
+    infof(data, "sread: EAGAIN or EWOULDBLOCK");
   }
   else if(io_error) {
-    failf(data, "reading from socket: %s", strerror(io_error));
+    char buffer[STRERROR_LEN];
+    failf(data, "reading from socket: %s",
+          Curl_strerror(io_error, buffer, sizeof(buffer)));
     *err = CURLE_READ_ERROR;
     return -1;
   }
@@ -142,7 +144,7 @@ cr_recv(struct Curl_easy *data, int sockindex,
     return -1;
   }
 
-  infof(data, "cr_recv read %ld bytes from the network\n", tls_bytes_read);
+  infof(data, "cr_recv read %ld bytes from the network", tls_bytes_read);
 
   rresult = rustls_connection_process_new_packets(rconn);
   if(rresult != RUSTLS_RESULT_OK) {
@@ -173,12 +175,12 @@ cr_recv(struct Curl_easy *data, int sockindex,
         available data has been read." If we bring in more ciphertext with
         read_tls, more plaintext will become available. So don't tell curl
         this is an EOF. Instead, say "come back later." */
-      infof(data, "cr_recv got 0 bytes of plaintext\n");
+      infof(data, "cr_recv got 0 bytes of plaintext");
       backend->data_pending = FALSE;
       break;
     }
     else {
-      infof(data, "cr_recv copied out %ld bytes of plaintext\n", n);
+      infof(data, "cr_recv copied out %ld bytes of plaintext", n);
       plain_bytes_copied += n;
     }
   }
@@ -218,7 +220,7 @@ cr_send(struct Curl_easy *data, int sockindex,
   rustls_result rresult;
   rustls_io_result io_error;
 
-  infof(data, "cr_send %ld bytes of plaintext\n", plainlen);
+  infof(data, "cr_send %ld bytes of plaintext", plainlen);
 
   if(plainlen > 0) {
     rresult = rustls_connection_write(rconn, plainbuf, plainlen,
@@ -239,12 +241,14 @@ cr_send(struct Curl_easy *data, int sockindex,
     io_error = rustls_connection_write_tls(rconn, write_cb,
       &conn->sock[sockindex], &tlswritten);
     if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
-      infof(data, "swrite: EAGAIN after %ld bytes\n", tlswritten_total);
+      infof(data, "swrite: EAGAIN after %ld bytes", tlswritten_total);
       *err = CURLE_AGAIN;
       return -1;
     }
     else if(io_error) {
-      failf(data, "writing to socket: %s", strerror(io_error));
+      char buffer[STRERROR_LEN];
+      failf(data, "writing to socket: %s",
+            Curl_strerror(io_error, buffer, sizeof(buffer)));
       *err = CURLE_WRITE_ERROR;
       return -1;
     }
@@ -253,7 +257,7 @@ cr_send(struct Curl_easy *data, int sockindex,
       *err = CURLE_WRITE_ERROR;
       return -1;
     }
-    infof(data, "cr_send wrote %ld bytes to network\n", tlswritten);
+    infof(data, "cr_send wrote %ld bytes to network", tlswritten);
     tlswritten_total += tlswritten;
   }
 
@@ -304,10 +308,10 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
 
   config_builder = rustls_client_config_builder_new();
 #ifdef USE_HTTP2
-  infof(data, "offering ALPN for HTTP/1.1 and HTTP/2\n");
+  infof(data, "offering ALPN for HTTP/1.1 and HTTP/2");
   rustls_client_config_builder_set_protocols(config_builder, alpn, 2);
 #else
-  infof(data, "offering ALPN for HTTP/1.1 only\n");
+  infof(data, "offering ALPN for HTTP/1.1 only");
   rustls_client_config_builder_set_protocols(config_builder, alpn, 1);
 #endif
   if(!verifypeer) {
@@ -332,15 +336,6 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
       return CURLE_SSL_CACERT_BADFILE;
     }
   }
-  else {
-    result = rustls_client_config_builder_load_native_roots(config_builder);
-    if(result != RUSTLS_RESULT_OK) {
-      failf(data, "failed to load trusted certificates");
-      rustls_client_config_free(
-        rustls_client_config_builder_build(config_builder));
-      return CURLE_SSL_CACERT_BADFILE;
-    }
-  }
 
   backend->config = rustls_client_config_builder_build(config_builder);
   DEBUGASSERT(rconn == NULL);
@@ -364,24 +359,24 @@ cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn,
 
   rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
   if(NULL == protocol) {
-    infof(data, "ALPN, server did not agree to a protocol\n");
+    infof(data, "ALPN, server did not agree to a protocol");
     return;
   }
 
 #ifdef USE_HTTP2
   if(len == ALPN_H2_LENGTH && 0 == memcmp(ALPN_H2, protocol, len)) {
-    infof(data, "ALPN, negotiated h2\n");
+    infof(data, "ALPN, negotiated h2");
     conn->negnpn = CURL_HTTP_VERSION_2;
   }
   else
 #endif
   if(len == ALPN_HTTP_1_1_LENGTH &&
       0 == memcmp(ALPN_HTTP_1_1, protocol, len)) {
-    infof(data, "ALPN, negotiated http/1.1\n");
+    infof(data, "ALPN, negotiated http/1.1");
     conn->negnpn = CURL_HTTP_VERSION_1_1;
   }
   else {
-    infof(data, "ALPN, negotiated an unrecognized protocol\n");
+    infof(data, "ALPN, negotiated an unrecognized protocol");
   }
 
   Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
@@ -424,7 +419,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
     * once the handshake is done.
     */
     if(!rustls_connection_is_handshaking(rconn)) {
-      infof(data, "Done handshaking\n");
+      infof(data, "Done handshaking");
       /* Done with the handshake. Set up callbacks to send/receive data. */
       connssl->state = ssl_connection_complete;
 
@@ -449,22 +444,19 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
       return CURLE_SSL_CONNECT_ERROR;
     }
     if(0 == what) {
-      infof(data, "Curl_socket_check: %s would block\n",
-          wants_read&&wants_write ?
-            "writing and reading" :
-            wants_write ?
-              "writing" :
-              "reading");
+      infof(data, "Curl_socket_check: %s would block",
+            wants_read&&wants_write ? "writing and reading" :
+            wants_write ? "writing" : "reading");
       *done = FALSE;
       return CURLE_OK;
     }
     /* socket is readable or writable */
 
     if(wants_write) {
-      infof(data, "rustls_connection wants us to write_tls.\n");
+      infof(data, "rustls_connection wants us to write_tls.");
       cr_send(data, sockindex, NULL, 0, &tmperr);
       if(tmperr == CURLE_AGAIN) {
-        infof(data, "writing would block\n");
+        infof(data, "writing would block");
         /* fall through */
       }
       else if(tmperr != CURLE_OK) {
@@ -473,11 +465,11 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
     }
 
     if(wants_read) {
-      infof(data, "rustls_connection wants us to read_tls.\n");
+      infof(data, "rustls_connection wants us to read_tls.");
 
       cr_recv(data, sockindex, NULL, 0, &tmperr);
       if(tmperr == CURLE_AGAIN) {
-        infof(data, "reading would block\n");
+        infof(data, "reading would block");
         /* fall through */
       }
       else if(tmperr != CURLE_OK) {
index 3286a9e..722a937 100644 (file)
 #  define CALG_SHA_256 0x0000800c
 #endif
 
+/* Work around typo in classic MinGW's w32api up to version 5.0,
+   see https://osdn.net/projects/mingw/ticket/38391 */
+#if !defined(ALG_CLASS_DHASH) && defined(ALG_CLASS_HASH)
+#define ALG_CLASS_DHASH ALG_CLASS_HASH
+#endif
+
 #define BACKEND connssl->backend
 
 static Curl_recv schannel_recv;
@@ -279,13 +285,7 @@ get_alg_id_by_name(char *name)
 #ifdef CALG_HMAC
   CIPHEROPTION(CALG_HMAC);
 #endif
-#if !defined(__W32API_MAJOR_VERSION) ||                                 \
-  !defined(__W32API_MINOR_VERSION) ||                                   \
-  defined(__MINGW64_VERSION_MAJOR) ||                                   \
-  (__W32API_MAJOR_VERSION > 5)     ||                                   \
-  ((__W32API_MAJOR_VERSION == 5) && (__W32API_MINOR_VERSION > 0))
-  /* CALG_TLS1PRF has a syntax error in MinGW's w32api up to version 5.0,
-     see https://osdn.net/projects/mingw/ticket/38391 */
+#ifdef CALG_TLS1PRF
   CIPHEROPTION(CALG_TLS1PRF);
 #endif
 #ifdef CALG_HASH_REPLACE_OWF
@@ -372,23 +372,23 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
 
   store_name_len = sep - path;
 
-  if(_tcsnccmp(path, TEXT("CurrentUser"), store_name_len) == 0)
+  if(_tcsncmp(path, TEXT("CurrentUser"), store_name_len) == 0)
     *store_name = CERT_SYSTEM_STORE_CURRENT_USER;
-  else if(_tcsnccmp(path, TEXT("LocalMachine"), store_name_len) == 0)
+  else if(_tcsncmp(path, TEXT("LocalMachine"), store_name_len) == 0)
     *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE;
-  else if(_tcsnccmp(path, TEXT("CurrentService"), store_name_len) == 0)
+  else if(_tcsncmp(path, TEXT("CurrentService"), store_name_len) == 0)
     *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE;
-  else if(_tcsnccmp(path, TEXT("Services"), store_name_len) == 0)
+  else if(_tcsncmp(path, TEXT("Services"), store_name_len) == 0)
     *store_name = CERT_SYSTEM_STORE_SERVICES;
-  else if(_tcsnccmp(path, TEXT("Users"), store_name_len) == 0)
+  else if(_tcsncmp(path, TEXT("Users"), store_name_len) == 0)
     *store_name = CERT_SYSTEM_STORE_USERS;
-  else if(_tcsnccmp(path, TEXT("CurrentUserGroupPolicy"),
+  else if(_tcsncmp(path, TEXT("CurrentUserGroupPolicy"),
                     store_name_len) == 0)
     *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
-  else if(_tcsnccmp(path, TEXT("LocalMachineGroupPolicy"),
+  else if(_tcsncmp(path, TEXT("LocalMachineGroupPolicy"),
                     store_name_len) == 0)
     *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
-  else if(_tcsnccmp(path, TEXT("LocalMachineEnterprise"),
+  else if(_tcsncmp(path, TEXT("LocalMachineEnterprise"),
                     store_name_len) == 0)
     *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
   else
@@ -413,6 +413,341 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
   return CURLE_OK;
 }
 #endif
+static CURLcode
+schannel_acquire_credential_handle(struct Curl_easy *data,
+                                   struct connectdata *conn,
+                                   int sockindex)
+{
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  SCHANNEL_CRED schannel_cred;
+  PCCERT_CONTEXT client_certs[1] = { NULL };
+  SECURITY_STATUS sspi_status = SEC_E_OK;
+  CURLcode result;
+
+  /* setup Schannel API options */
+  memset(&schannel_cred, 0, sizeof(schannel_cred));
+  schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
+
+  if(conn->ssl_config.verifypeer) {
+#ifdef HAS_MANUAL_VERIFY_API
+    if(BACKEND->use_manual_cred_validation)
+      schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
+    else
+#endif
+      schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
+
+    if(SSL_SET_OPTION(no_revoke)) {
+      schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+        SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+
+      DEBUGF(infof(data, "schannel: disabled server certificate revocation "
+                   "checks"));
+    }
+    else if(SSL_SET_OPTION(revoke_best_effort)) {
+      schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+        SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
+
+      DEBUGF(infof(data, "schannel: ignore revocation offline errors"));
+    }
+    else {
+      schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
+
+      DEBUGF(infof(data,
+                   "schannel: checking server certificate revocation"));
+    }
+  }
+  else {
+    schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
+      SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+      SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+    DEBUGF(infof(data,
+                 "schannel: disabled server cert revocation checks"));
+  }
+
+  if(!conn->ssl_config.verifyhost) {
+    schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
+    DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
+                 "comparing the supplied target name with the subject "
+                 "names in server certificates."));
+  }
+
+  if(!SSL_SET_OPTION(auto_client_cert)) {
+    schannel_cred.dwFlags &= ~SCH_CRED_USE_DEFAULT_CREDS;
+    schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
+    infof(data, "schannel: disabled automatic use of client certificate");
+  }
+  else
+    infof(data, "schannel: enabled automatic use of client certificate");
+
+  switch(conn->ssl_config.version) {
+  case CURL_SSLVERSION_DEFAULT:
+  case CURL_SSLVERSION_TLSv1:
+  case CURL_SSLVERSION_TLSv1_0:
+  case CURL_SSLVERSION_TLSv1_1:
+  case CURL_SSLVERSION_TLSv1_2:
+  case CURL_SSLVERSION_TLSv1_3:
+  {
+    result = set_ssl_version_min_max(&schannel_cred, data, conn);
+    if(result != CURLE_OK)
+      return result;
+    break;
+  }
+  case CURL_SSLVERSION_SSLv3:
+  case CURL_SSLVERSION_SSLv2:
+    failf(data, "SSL versions not supported");
+    return CURLE_NOT_BUILT_IN;
+  default:
+    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  if(SSL_CONN_CONFIG(cipher_list)) {
+    result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list),
+                             BACKEND->algIds);
+    if(CURLE_OK != result) {
+      failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
+      return result;
+    }
+  }
+
+
+#ifdef HAS_CLIENT_CERT_PATH
+  /* client certificate */
+  if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
+    DWORD cert_store_name = 0;
+    TCHAR *cert_store_path = NULL;
+    TCHAR *cert_thumbprint_str = NULL;
+    CRYPT_HASH_BLOB cert_thumbprint;
+    BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
+    HCERTSTORE cert_store = NULL;
+    FILE *fInCert = NULL;
+    void *certdata = NULL;
+    size_t certsize = 0;
+    bool blob = data->set.ssl.primary.cert_blob != NULL;
+    TCHAR *cert_path = NULL;
+    if(blob) {
+      certdata = data->set.ssl.primary.cert_blob->data;
+      certsize = data->set.ssl.primary.cert_blob->len;
+    }
+    else {
+      cert_path = curlx_convert_UTF8_to_tchar(
+        data->set.ssl.primary.clientcert);
+      if(!cert_path)
+        return CURLE_OUT_OF_MEMORY;
+
+      result = get_cert_location(cert_path, &cert_store_name,
+        &cert_store_path, &cert_thumbprint_str);
+
+      if(result && (data->set.ssl.primary.clientcert[0]!='\0'))
+        fInCert = fopen(data->set.ssl.primary.clientcert, "rb");
+
+      if(result && !fInCert) {
+        failf(data, "schannel: Failed to get certificate location"
+              " or file for %s",
+              data->set.ssl.primary.clientcert);
+        curlx_unicodefree(cert_path);
+        return result;
+      }
+    }
+
+    if((fInCert || blob) && (data->set.ssl.cert_type) &&
+        (!strcasecompare(data->set.ssl.cert_type, "P12"))) {
+      failf(data, "schannel: certificate format compatibility error "
+              " for %s",
+              blob ? "(memory blob)" : data->set.ssl.primary.clientcert);
+      curlx_unicodefree(cert_path);
+      return CURLE_SSL_CERTPROBLEM;
+    }
+
+    if(fInCert || blob) {
+      /* Reading a .P12 or .pfx file, like the example at bottom of
+           https://social.msdn.microsoft.com/Forums/windowsdesktop/
+                          en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
+      */
+      CRYPT_DATA_BLOB datablob;
+      WCHAR* pszPassword;
+      size_t pwd_len = 0;
+      int str_w_len = 0;
+      const char *cert_showfilename_error = blob ?
+        "(memory blob)" : data->set.ssl.primary.clientcert;
+      curlx_unicodefree(cert_path);
+      if(fInCert) {
+        long cert_tell = 0;
+        bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
+        if(continue_reading)
+          cert_tell = ftell(fInCert);
+        if(cert_tell < 0)
+          continue_reading = FALSE;
+        else
+          certsize = (size_t)cert_tell;
+        if(continue_reading)
+          continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
+        if(continue_reading)
+          certdata = malloc(certsize + 1);
+        if((!certdata) ||
+           ((int) fread(certdata, certsize, 1, fInCert) != 1))
+          continue_reading = FALSE;
+        fclose(fInCert);
+        if(!continue_reading) {
+          failf(data, "schannel: Failed to read cert file %s",
+              data->set.ssl.primary.clientcert);
+          free(certdata);
+          return CURLE_SSL_CERTPROBLEM;
+        }
+      }
+
+      /* Convert key-pair data to the in-memory certificate store */
+      datablob.pbData = (BYTE*)certdata;
+      datablob.cbData = (DWORD)certsize;
+
+      if(data->set.ssl.key_passwd != NULL)
+        pwd_len = strlen(data->set.ssl.key_passwd);
+      pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
+      if(pszPassword) {
+        if(pwd_len > 0)
+          str_w_len = MultiByteToWideChar(CP_UTF8,
+             MB_ERR_INVALID_CHARS,
+             data->set.ssl.key_passwd, (int)pwd_len,
+             pszPassword, (int)(pwd_len + 1));
+
+        if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
+          pszPassword[str_w_len] = 0;
+        else
+          pszPassword[0] = 0;
+
+        cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
+        free(pszPassword);
+      }
+      if(!blob)
+        free(certdata);
+      if(!cert_store) {
+        DWORD errorcode = GetLastError();
+        if(errorcode == ERROR_INVALID_PASSWORD)
+          failf(data, "schannel: Failed to import cert file %s, "
+                "password is bad",
+                cert_showfilename_error);
+        else
+          failf(data, "schannel: Failed to import cert file %s, "
+                "last error is 0x%x",
+                cert_showfilename_error, errorcode);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+
+      client_certs[0] = CertFindCertificateInStore(
+        cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
+        CERT_FIND_ANY, NULL, NULL);
+
+      if(!client_certs[0]) {
+        failf(data, "schannel: Failed to get certificate from file %s"
+              ", last error is 0x%x",
+              cert_showfilename_error, GetLastError());
+        CertCloseStore(cert_store, 0);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+
+      schannel_cred.cCreds = 1;
+      schannel_cred.paCred = client_certs;
+    }
+    else {
+      cert_store =
+        CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
+                      (HCRYPTPROV)NULL,
+                      CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
+                      cert_store_path);
+      if(!cert_store) {
+        failf(data, "schannel: Failed to open cert store %x %s, "
+              "last error is 0x%x",
+              cert_store_name, cert_store_path, GetLastError());
+        free(cert_store_path);
+        curlx_unicodefree(cert_path);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+      free(cert_store_path);
+
+      cert_thumbprint.pbData = cert_thumbprint_data;
+      cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
+
+      if(!CryptStringToBinary(cert_thumbprint_str,
+                              CERT_THUMBPRINT_STR_LEN,
+                              CRYPT_STRING_HEX,
+                              cert_thumbprint_data,
+                              &cert_thumbprint.cbData,
+                              NULL, NULL)) {
+        curlx_unicodefree(cert_path);
+        CertCloseStore(cert_store, 0);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+
+      client_certs[0] = CertFindCertificateInStore(
+        cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
+        CERT_FIND_HASH, &cert_thumbprint, NULL);
+
+      curlx_unicodefree(cert_path);
+
+      if(client_certs[0]) {
+        schannel_cred.cCreds = 1;
+        schannel_cred.paCred = client_certs;
+      }
+      else {
+        /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
+        CertCloseStore(cert_store, 0);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+    }
+    CertCloseStore(cert_store, 0);
+  }
+#else
+  if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
+    failf(data, "schannel: client cert support not built in");
+    return CURLE_NOT_BUILT_IN;
+  }
+#endif
+
+  /* allocate memory for the re-usable credential handle */
+  BACKEND->cred = (struct Curl_schannel_cred *)
+    calloc(1, sizeof(struct Curl_schannel_cred));
+  if(!BACKEND->cred) {
+    failf(data, "schannel: unable to allocate memory");
+
+    if(client_certs[0])
+      CertFreeCertificateContext(client_certs[0]);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+  BACKEND->cred->refcount = 1;
+
+  /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
+   */
+  sspi_status =
+    s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
+                                       SECPKG_CRED_OUTBOUND, NULL,
+                                       &schannel_cred, NULL, NULL,
+                                       &BACKEND->cred->cred_handle,
+                                       &BACKEND->cred->time_stamp);
+
+  if(client_certs[0])
+    CertFreeCertificateContext(client_certs[0]);
+
+  if(sspi_status != SEC_E_OK) {
+    char buffer[STRERROR_LEN];
+    failf(data, "schannel: AcquireCredentialsHandle failed: %s",
+          Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+    Curl_safefree(BACKEND->cred);
+    switch(sspi_status) {
+    case SEC_E_INSUFFICIENT_MEMORY:
+      return CURLE_OUT_OF_MEMORY;
+    case SEC_E_NO_CREDENTIALS:
+    case SEC_E_SECPKG_NOT_FOUND:
+    case SEC_E_NOT_OWNER:
+    case SEC_E_UNKNOWN_CREDENTIALS:
+    case SEC_E_INTERNAL_ERROR:
+    default:
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+
+  return CURLE_OK;
+}
 
 static CURLcode
 schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
@@ -427,8 +762,6 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
 #ifdef HAS_ALPN
   unsigned char alpn_buffer[128];
 #endif
-  SCHANNEL_CRED schannel_cred;
-  PCCERT_CONTEXT client_certs[1] = { NULL };
   SECURITY_STATUS sspi_status = SEC_E_OK;
   struct Curl_schannel_cred *old_cred = NULL;
   struct in_addr addr;
@@ -440,7 +773,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
   char * const hostname = SSL_HOST_NAME();
 
   DEBUGF(infof(data,
-               "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
+               "schannel: SSL/TLS connection with %s port %hu (step 1/3)",
                hostname, conn->remote_port));
 
   if(curlx_verify_windows_version(5, 1, PLATFORM_WINNT,
@@ -448,7 +781,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
     /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
        algorithms that may not be supported by all servers. */
     infof(data, "schannel: Windows version is old and may not be able to "
-          "connect to some servers due to lack of SNI, algorithms, etc.\n");
+          "connect to some servers due to lack of SNI, algorithms, etc.");
   }
 
 #ifdef HAS_ALPN
@@ -503,338 +836,21 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
                               SSL_IS_PROXY() ? TRUE : FALSE,
                               (void **)&old_cred, NULL, sockindex)) {
       BACKEND->cred = old_cred;
-      DEBUGF(infof(data, "schannel: re-using existing credential handle\n"));
+      DEBUGF(infof(data, "schannel: re-using existing credential handle"));
 
       /* increment the reference counter of the credential/session handle */
       BACKEND->cred->refcount++;
       DEBUGF(infof(data,
-                   "schannel: incremented credential handle refcount = %d\n",
+                   "schannel: incremented credential handle refcount = %d",
                    BACKEND->cred->refcount));
     }
     Curl_ssl_sessionid_unlock(data);
   }
 
   if(!BACKEND->cred) {
-    /* setup Schannel API options */
-    memset(&schannel_cred, 0, sizeof(schannel_cred));
-    schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
-
-    if(conn->ssl_config.verifypeer) {
-#ifdef HAS_MANUAL_VERIFY_API
-      if(BACKEND->use_manual_cred_validation)
-        schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
-      else
-#endif
-        schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
-
-      if(SSL_SET_OPTION(no_revoke)) {
-        schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
-          SCH_CRED_IGNORE_REVOCATION_OFFLINE;
-
-        DEBUGF(infof(data, "schannel: disabled server certificate revocation "
-                     "checks\n"));
-      }
-      else if(SSL_SET_OPTION(revoke_best_effort)) {
-        schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
-          SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
-
-        DEBUGF(infof(data, "schannel: ignore revocation offline errors"));
-      }
-      else {
-        schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
-
-        DEBUGF(infof(data,
-                     "schannel: checking server certificate revocation\n"));
-      }
-    }
-    else {
-      schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
-        SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
-        SCH_CRED_IGNORE_REVOCATION_OFFLINE;
-      DEBUGF(infof(data,
-                   "schannel: disabled server cert revocation checks\n"));
-    }
-
-    if(!conn->ssl_config.verifyhost) {
-      schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
-      DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
-                   "comparing the supplied target name with the subject "
-                   "names in server certificates.\n"));
-    }
-
-    if(!SSL_SET_OPTION(auto_client_cert)) {
-      schannel_cred.dwFlags &= ~SCH_CRED_USE_DEFAULT_CREDS;
-      schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
-      infof(data, "schannel: disabled automatic use of client certificate\n");
-    }
-    else
-      infof(data, "schannel: enabled automatic use of client certificate\n");
-
-    switch(conn->ssl_config.version) {
-    case CURL_SSLVERSION_DEFAULT:
-    case CURL_SSLVERSION_TLSv1:
-    case CURL_SSLVERSION_TLSv1_0:
-    case CURL_SSLVERSION_TLSv1_1:
-    case CURL_SSLVERSION_TLSv1_2:
-    case CURL_SSLVERSION_TLSv1_3:
-    {
-      result = set_ssl_version_min_max(&schannel_cred, data, conn);
-      if(result != CURLE_OK)
-        return result;
-      break;
-    }
-    case CURL_SSLVERSION_SSLv3:
-    case CURL_SSLVERSION_SSLv2:
-      failf(data, "SSL versions not supported");
-      return CURLE_NOT_BUILT_IN;
-    default:
-      failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
-      return CURLE_SSL_CONNECT_ERROR;
-    }
-
-    if(SSL_CONN_CONFIG(cipher_list)) {
-      result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list),
-                               BACKEND->algIds);
-      if(CURLE_OK != result) {
-        failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
-        return result;
-      }
-    }
-
-
-#ifdef HAS_CLIENT_CERT_PATH
-    /* client certificate */
-    if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
-      DWORD cert_store_name = 0;
-      TCHAR *cert_store_path = NULL;
-      TCHAR *cert_thumbprint_str = NULL;
-      CRYPT_HASH_BLOB cert_thumbprint;
-      BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
-      HCERTSTORE cert_store = NULL;
-      FILE *fInCert = NULL;
-      void *certdata = NULL;
-      size_t certsize = 0;
-      bool blob = data->set.ssl.primary.cert_blob != NULL;
-      TCHAR *cert_path = NULL;
-      if(blob) {
-        certdata = data->set.ssl.primary.cert_blob->data;
-        certsize = data->set.ssl.primary.cert_blob->len;
-      }
-      else {
-        cert_path = curlx_convert_UTF8_to_tchar(
-          data->set.ssl.primary.clientcert);
-        if(!cert_path)
-          return CURLE_OUT_OF_MEMORY;
-
-        result = get_cert_location(cert_path, &cert_store_name,
-          &cert_store_path, &cert_thumbprint_str);
-
-        if(result && (data->set.ssl.primary.clientcert[0]!='\0'))
-          fInCert = fopen(data->set.ssl.primary.clientcert, "rb");
-
-        if(result && !fInCert) {
-          failf(data, "schannel: Failed to get certificate location"
-                " or file for %s",
-                data->set.ssl.primary.clientcert);
-          curlx_unicodefree(cert_path);
-          return result;
-        }
-      }
-
-      if((fInCert || blob) && (data->set.ssl.cert_type) &&
-          (!strcasecompare(data->set.ssl.cert_type, "P12"))) {
-        failf(data, "schannel: certificate format compatibility error "
-                " for %s",
-                blob ? "(memory blob)" : data->set.ssl.primary.clientcert);
-        curlx_unicodefree(cert_path);
-        return CURLE_SSL_CERTPROBLEM;
-      }
-
-      if(fInCert || blob) {
-        /* Reading a .P12 or .pfx file, like the example at bottom of
-             https://social.msdn.microsoft.com/Forums/windowsdesktop/
-                            en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
-        */
-        CRYPT_DATA_BLOB datablob;
-        WCHAR* pszPassword;
-        size_t pwd_len = 0;
-        int str_w_len = 0;
-        const char *cert_showfilename_error = blob ?
-          "(memory blob)" : data->set.ssl.primary.clientcert;
-        curlx_unicodefree(cert_path);
-        if(fInCert) {
-          long cert_tell = 0;
-          bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
-          if(continue_reading)
-            cert_tell = ftell(fInCert);
-          if(cert_tell < 0)
-            continue_reading = FALSE;
-          else
-            certsize = (size_t)cert_tell;
-          if(continue_reading)
-            continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
-          if(continue_reading)
-            certdata = malloc(certsize + 1);
-          if((!certdata) ||
-             ((int) fread(certdata, certsize, 1, fInCert) != 1))
-            continue_reading = FALSE;
-          fclose(fInCert);
-          if(!continue_reading) {
-            failf(data, "schannel: Failed to read cert file %s",
-                data->set.ssl.primary.clientcert);
-            free(certdata);
-            return CURLE_SSL_CERTPROBLEM;
-          }
-        }
-
-        /* Convert key-pair data to the in-memory certificate store */
-        datablob.pbData = (BYTE*)certdata;
-        datablob.cbData = (DWORD)certsize;
-
-        if(data->set.ssl.key_passwd != NULL)
-          pwd_len = strlen(data->set.ssl.key_passwd);
-        pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
-        if(pszPassword) {
-          if(pwd_len > 0)
-            str_w_len = MultiByteToWideChar(CP_UTF8,
-               MB_ERR_INVALID_CHARS,
-               data->set.ssl.key_passwd, (int)pwd_len,
-               pszPassword, (int)(pwd_len + 1));
-
-          if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
-            pszPassword[str_w_len] = 0;
-          else
-            pszPassword[0] = 0;
-
-          cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
-          free(pszPassword);
-        }
-        if(!blob)
-          free(certdata);
-        if(!cert_store) {
-          DWORD errorcode = GetLastError();
-          if(errorcode == ERROR_INVALID_PASSWORD)
-            failf(data, "schannel: Failed to import cert file %s, "
-                  "password is bad",
-                  cert_showfilename_error);
-          else
-            failf(data, "schannel: Failed to import cert file %s, "
-                  "last error is 0x%x",
-                  cert_showfilename_error, errorcode);
-          return CURLE_SSL_CERTPROBLEM;
-        }
-
-        client_certs[0] = CertFindCertificateInStore(
-          cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
-          CERT_FIND_ANY, NULL, NULL);
-
-        if(!client_certs[0]) {
-          failf(data, "schannel: Failed to get certificate from file %s"
-                ", last error is 0x%x",
-                cert_showfilename_error, GetLastError());
-          CertCloseStore(cert_store, 0);
-          return CURLE_SSL_CERTPROBLEM;
-        }
-
-        schannel_cred.cCreds = 1;
-        schannel_cred.paCred = client_certs;
-      }
-      else {
-        cert_store =
-          CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
-                        (HCRYPTPROV)NULL,
-                        CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
-                        cert_store_path);
-        if(!cert_store) {
-          failf(data, "schannel: Failed to open cert store %x %s, "
-                "last error is 0x%x",
-                cert_store_name, cert_store_path, GetLastError());
-          free(cert_store_path);
-          curlx_unicodefree(cert_path);
-          return CURLE_SSL_CERTPROBLEM;
-        }
-        free(cert_store_path);
-
-        cert_thumbprint.pbData = cert_thumbprint_data;
-        cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
-
-        if(!CryptStringToBinary(cert_thumbprint_str,
-                                CERT_THUMBPRINT_STR_LEN,
-                                CRYPT_STRING_HEX,
-                                cert_thumbprint_data,
-                                &cert_thumbprint.cbData,
-                                NULL, NULL)) {
-          curlx_unicodefree(cert_path);
-          CertCloseStore(cert_store, 0);
-          return CURLE_SSL_CERTPROBLEM;
-        }
-
-        client_certs[0] = CertFindCertificateInStore(
-          cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
-          CERT_FIND_HASH, &cert_thumbprint, NULL);
-
-        curlx_unicodefree(cert_path);
-
-        if(client_certs[0]) {
-          schannel_cred.cCreds = 1;
-          schannel_cred.paCred = client_certs;
-        }
-        else {
-          /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
-          CertCloseStore(cert_store, 0);
-          return CURLE_SSL_CERTPROBLEM;
-        }
-      }
-      CertCloseStore(cert_store, 0);
-    }
-#else
-    if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
-      failf(data, "schannel: client cert support not built in");
-      return CURLE_NOT_BUILT_IN;
-    }
-#endif
-
-    /* allocate memory for the re-usable credential handle */
-    BACKEND->cred = (struct Curl_schannel_cred *)
-      calloc(1, sizeof(struct Curl_schannel_cred));
-    if(!BACKEND->cred) {
-      failf(data, "schannel: unable to allocate memory");
-
-      if(client_certs[0])
-        CertFreeCertificateContext(client_certs[0]);
-
-      return CURLE_OUT_OF_MEMORY;
-    }
-    BACKEND->cred->refcount = 1;
-
-    /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
-     */
-    sspi_status =
-      s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
-                                         SECPKG_CRED_OUTBOUND, NULL,
-                                         &schannel_cred, NULL, NULL,
-                                         &BACKEND->cred->cred_handle,
-                                         &BACKEND->cred->time_stamp);
-
-    if(client_certs[0])
-      CertFreeCertificateContext(client_certs[0]);
-
-    if(sspi_status != SEC_E_OK) {
-      char buffer[STRERROR_LEN];
-      failf(data, "schannel: AcquireCredentialsHandle failed: %s",
-            Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
-      Curl_safefree(BACKEND->cred);
-      switch(sspi_status) {
-      case SEC_E_INSUFFICIENT_MEMORY:
-        return CURLE_OUT_OF_MEMORY;
-      case SEC_E_NO_CREDENTIALS:
-      case SEC_E_SECPKG_NOT_FOUND:
-      case SEC_E_NOT_OWNER:
-      case SEC_E_UNKNOWN_CREDENTIALS:
-      case SEC_E_INTERNAL_ERROR:
-      default:
-        return CURLE_SSL_CONNECT_ERROR;
-      }
+    result = schannel_acquire_credential_handle(data, conn, sockindex);
+    if(result != CURLE_OK) {
+      return result;
     }
   }
 
@@ -844,7 +860,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
      || Curl_inet_pton(AF_INET6, hostname, &addr6)
 #endif
     ) {
-    infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
+    infof(data, "schannel: using IP address, SNI is not supported by OS.");
   }
 
 #ifdef HAS_ALPN
@@ -877,14 +893,14 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
       alpn_buffer[cur++] = ALPN_H2_LENGTH;
       memcpy(&alpn_buffer[cur], ALPN_H2, ALPN_H2_LENGTH);
       cur += ALPN_H2_LENGTH;
-      infof(data, "schannel: ALPN, offering %s\n", ALPN_H2);
+      infof(data, "schannel: ALPN, offering %s", ALPN_H2);
     }
 #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);
+    infof(data, "schannel: ALPN, offering %s", ALPN_HTTP_1_1);
 
     *list_len = curlx_uitous(cur - list_start_index);
     *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
@@ -972,7 +988,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
   }
 
   DEBUGF(infof(data, "schannel: sending initial handshake data: "
-               "sending %lu bytes...\n", outbuf.cbBuffer));
+               "sending %lu bytes.", outbuf.cbBuffer));
 
   /* send initial handshake data which is now stored in output buffer */
   result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
@@ -985,7 +1001,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
   }
 
   DEBUGF(infof(data, "schannel: sent initial handshake data: "
-               "sent %zd bytes\n", written));
+               "sent %zd bytes", written));
 
   BACKEND->recv_unrecoverable_err = CURLE_OK;
   BACKEND->recv_sspi_close_notify = false;
@@ -1019,7 +1035,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
   doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
 
   DEBUGF(infof(data,
-               "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
+               "schannel: SSL/TLS connection with %s port %hu (step 2/3)",
                hostname, conn->remote_port));
 
   if(!BACKEND->cred || !BACKEND->ctxt)
@@ -1081,7 +1097,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
         if(connssl->connecting_state != ssl_connect_2_writing)
           connssl->connecting_state = ssl_connect_2_reading;
         DEBUGF(infof(data, "schannel: failed to receive handshake, "
-                     "need more data\n"));
+                     "need more data"));
         return CURLE_OK;
       }
       else if((result != CURLE_OK) || (nread == 0)) {
@@ -1093,11 +1109,11 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
       /* increase encrypted data buffer offset */
       BACKEND->encdata_offset += nread;
       BACKEND->encdata_is_incomplete = false;
-      DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
+      DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
     }
 
     DEBUGF(infof(data,
-                 "schannel: encrypted data buffer: offset %zu length %zu\n",
+                 "schannel: encrypted data buffer: offset %zu length %zu",
                  BACKEND->encdata_offset, BACKEND->encdata_length));
 
     /* setup input buffers */
@@ -1142,7 +1158,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
       BACKEND->encdata_is_incomplete = true;
       connssl->connecting_state = ssl_connect_2_reading;
       DEBUGF(infof(data,
-                   "schannel: received incomplete message, need more data\n"));
+                   "schannel: received incomplete message, need more data"));
       return CURLE_OK;
     }
 
@@ -1154,7 +1170,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
       BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
       connssl->connecting_state = ssl_connect_2_writing;
       DEBUGF(infof(data,
-                   "schannel: a client certificate has been requested\n"));
+                   "schannel: a client certificate has been requested"));
       return CURLE_OK;
     }
 
@@ -1164,7 +1180,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
         /* search for handshake tokens that need to be send */
         if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
           DEBUGF(infof(data, "schannel: sending next handshake data: "
-                       "sending %lu bytes...\n", outbuf[i].cbBuffer));
+                       "sending %lu bytes.", outbuf[i].cbBuffer));
 
           /* send handshake token to server */
           result = Curl_write_plain(data, conn->sock[sockindex],
@@ -1219,7 +1235,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
 
     /* check if there was additional remaining encrypted data */
     if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
-      DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
+      DEBUGF(infof(data, "schannel: encrypted data length: %lu",
                    inbuf[1].cbBuffer));
       /*
         There are two cases where we could be getting extra data here:
@@ -1259,7 +1275,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
   /* check if the handshake is complete */
   if(sspi_status == SEC_E_OK) {
     connssl->connecting_state = ssl_connect_3;
-    DEBUGF(infof(data, "schannel: SSL/TLS handshake complete\n"));
+    DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
   }
 
   pubkey_ptr = SSL_PINNED_PUB_KEY();
@@ -1348,7 +1364,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
   SECURITY_STATUS sspi_status = SEC_E_OK;
   CERT_CONTEXT *ccert_context = NULL;
   bool isproxy = SSL_IS_PROXY();
-#ifdef DEBUGBUILD
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   const char * const hostname = SSL_HOST_NAME();
 #endif
 #ifdef HAS_ALPN
@@ -1358,7 +1374,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
 
   DEBUGF(infof(data,
-               "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
+               "schannel: SSL/TLS connection with %s port %hu (step 3/3)",
                hostname, conn->remote_port));
 
   if(!BACKEND->cred)
@@ -1394,7 +1410,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
     if(alpn_result.ProtoNegoStatus ==
        SecApplicationProtocolNegotiationStatus_Success) {
 
-      infof(data, "schannel: ALPN, server accepted to use %.*s\n",
+      infof(data, "schannel: ALPN, server accepted to use %.*s",
             alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
 
 #ifdef USE_HTTP2
@@ -1411,7 +1427,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
         }
     }
     else
-      infof(data, "ALPN, server did not agree to a protocol\n");
+      infof(data, "ALPN, server did not agree to a protocol");
     Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
   }
@@ -1428,7 +1444,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
     if(incache) {
       if(old_cred != BACKEND->cred) {
         DEBUGF(infof(data,
-                     "schannel: old credential handle is stale, removing\n"));
+                     "schannel: old credential handle is stale, removing"));
         /* we're not taking old_cred ownership here, no refcount++ is needed */
         Curl_ssl_delsessionid(data, (void *)old_cred);
         incache = FALSE;
@@ -1447,7 +1463,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
         /* this cred session is now also referenced by sessionid cache */
         BACKEND->cred->refcount++;
         DEBUGF(infof(data,
-                     "schannel: stored credential handle in session cache\n"));
+                     "schannel: stored credential handle in session cache"));
       }
     }
     Curl_ssl_sessionid_unlock(data);
@@ -1778,21 +1794,21 @@ schannel_recv(struct Curl_easy *data, int sockindex,
    * handled in the cleanup.
    */
 
-  DEBUGF(infof(data, "schannel: client wants to read %zu bytes\n", len));
+  DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
   *err = CURLE_OK;
 
   if(len && len <= BACKEND->decdata_offset) {
-    infof(data, "schannel: enough decrypted data is already available\n");
+    infof(data, "schannel: enough decrypted data is already available");
     goto cleanup;
   }
   else if(BACKEND->recv_unrecoverable_err) {
     *err = BACKEND->recv_unrecoverable_err;
-    infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
+    infof(data, "schannel: an unrecoverable error occurred in a prior call");
     goto cleanup;
   }
   else if(BACKEND->recv_sspi_close_notify) {
     /* once a server has indicated shutdown there is no more encrypted data */
-    infof(data, "schannel: server indicated shutdown in a prior call\n");
+    infof(data, "schannel: server indicated shutdown in a prior call");
     goto cleanup;
   }
 
@@ -1821,12 +1837,12 @@ schannel_recv(struct Curl_easy *data, int sockindex,
       BACKEND->encdata_buffer = reallocated_buffer;
       BACKEND->encdata_length = reallocated_length;
       size = BACKEND->encdata_length - BACKEND->encdata_offset;
-      DEBUGF(infof(data, "schannel: encdata_buffer resized %zu\n",
+      DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
                    BACKEND->encdata_length));
     }
 
     DEBUGF(infof(data,
-                 "schannel: encrypted data buffer: offset %zu length %zu\n",
+                 "schannel: encrypted data buffer: offset %zu length %zu",
                  BACKEND->encdata_offset, BACKEND->encdata_length));
 
     /* read encrypted data from socket */
@@ -1838,25 +1854,25 @@ schannel_recv(struct Curl_easy *data, int sockindex,
       nread = -1;
       if(*err == CURLE_AGAIN)
         DEBUGF(infof(data,
-                     "schannel: Curl_read_plain returned CURLE_AGAIN\n"));
+                     "schannel: Curl_read_plain returned CURLE_AGAIN"));
       else if(*err == CURLE_RECV_ERROR)
-        infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
+        infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR");
       else
-        infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
+        infof(data, "schannel: Curl_read_plain returned error %d", *err);
     }
     else if(nread == 0) {
       BACKEND->recv_connection_closed = true;
-      DEBUGF(infof(data, "schannel: server closed the connection\n"));
+      DEBUGF(infof(data, "schannel: server closed the connection"));
     }
     else if(nread > 0) {
       BACKEND->encdata_offset += (size_t)nread;
       BACKEND->encdata_is_incomplete = false;
-      DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
+      DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
     }
   }
 
   DEBUGF(infof(data,
-               "schannel: encrypted data buffer: offset %zu length %zu\n",
+               "schannel: encrypted data buffer: offset %zu length %zu",
                BACKEND->encdata_offset, BACKEND->encdata_length));
 
   /* decrypt loop */
@@ -1885,7 +1901,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
       /* check for successfully decrypted data, even before actual
          renegotiation or shutdown of the connection context */
       if(inbuf[1].BufferType == SECBUFFER_DATA) {
-        DEBUGF(infof(data, "schannel: decrypted data length: %lu\n",
+        DEBUGF(infof(data, "schannel: decrypted data length: %lu",
                      inbuf[1].cbBuffer));
 
         /* increase buffer in order to fit the received amount of data */
@@ -1918,15 +1934,15 @@ schannel_recv(struct Curl_easy *data, int sockindex,
           BACKEND->decdata_offset += size;
         }
 
-        DEBUGF(infof(data, "schannel: decrypted data added: %zu\n", size));
+        DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
         DEBUGF(infof(data,
-                     "schannel: decrypted cached: offset %zu length %zu\n",
+                     "schannel: decrypted cached: offset %zu length %zu",
                      BACKEND->decdata_offset, BACKEND->decdata_length));
       }
 
       /* check for remaining encrypted data */
       if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
-        DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
+        DEBUGF(infof(data, "schannel: encrypted data length: %lu",
                      inbuf[3].cbBuffer));
 
         /* check if the remaining data is less than the total amount
@@ -1942,7 +1958,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
         }
 
         DEBUGF(infof(data,
-                     "schannel: encrypted cached: offset %zu length %zu\n",
+                     "schannel: encrypted cached: offset %zu length %zu",
                      BACKEND->encdata_offset, BACKEND->encdata_length));
       }
       else {
@@ -1952,29 +1968,29 @@ schannel_recv(struct Curl_easy *data, int sockindex,
 
       /* check if server wants to renegotiate the connection context */
       if(sspi_status == SEC_I_RENEGOTIATE) {
-        infof(data, "schannel: remote party requests renegotiation\n");
+        infof(data, "schannel: remote party requests renegotiation");
         if(*err && *err != CURLE_AGAIN) {
-          infof(data, "schannel: can't renogotiate, an error is pending\n");
+          infof(data, "schannel: can't renogotiate, an error is pending");
           goto cleanup;
         }
         if(BACKEND->encdata_offset) {
           *err = CURLE_RECV_ERROR;
           infof(data, "schannel: can't renogotiate, "
-                "encrypted data available\n");
+                "encrypted data available");
           goto cleanup;
         }
         /* begin renegotiation */
-        infof(data, "schannel: renegotiating SSL/TLS connection\n");
+        infof(data, "schannel: renegotiating SSL/TLS connection");
         connssl->state = ssl_connection_negotiating;
         connssl->connecting_state = ssl_connect_2_writing;
         *err = schannel_connect_common(data, conn, sockindex, FALSE, &done);
         if(*err) {
-          infof(data, "schannel: renegotiation failed\n");
+          infof(data, "schannel: renegotiation failed");
           goto cleanup;
         }
         /* now retry receiving data */
         sspi_status = SEC_E_OK;
-        infof(data, "schannel: SSL/TLS connection renegotiated\n");
+        infof(data, "schannel: SSL/TLS connection renegotiated");
         continue;
       }
       /* check if the server closed the connection */
@@ -1984,7 +2000,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
         BACKEND->recv_sspi_close_notify = true;
         if(!BACKEND->recv_connection_closed) {
           BACKEND->recv_connection_closed = true;
-          infof(data, "schannel: server closed the connection\n");
+          infof(data, "schannel: server closed the connection");
         }
         goto cleanup;
       }
@@ -1993,7 +2009,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
       BACKEND->encdata_is_incomplete = true;
       if(!*err)
         *err = CURLE_AGAIN;
-      infof(data, "schannel: failed to decrypt data, need more data\n");
+      infof(data, "schannel: failed to decrypt data, need more data");
       goto cleanup;
     }
     else {
@@ -2001,23 +2017,23 @@ schannel_recv(struct Curl_easy *data, int sockindex,
       char buffer[STRERROR_LEN];
 #endif
       *err = CURLE_RECV_ERROR;
-      infof(data, "schannel: failed to read data from server: %s\n",
+      infof(data, "schannel: failed to read data from server: %s",
             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
       goto cleanup;
     }
   }
 
   DEBUGF(infof(data,
-               "schannel: encrypted data buffer: offset %zu length %zu\n",
+               "schannel: encrypted data buffer: offset %zu length %zu",
                BACKEND->encdata_offset, BACKEND->encdata_length));
 
   DEBUGF(infof(data,
-               "schannel: decrypted data buffer: offset %zu length %zu\n",
+               "schannel: decrypted data buffer: offset %zu length %zu",
                BACKEND->decdata_offset, BACKEND->decdata_length));
 
   cleanup:
   /* Warning- there is no guarantee the encdata state is valid at this point */
-  DEBUGF(infof(data, "schannel: schannel_recv cleanup\n"));
+  DEBUGF(infof(data, "schannel: schannel_recv cleanup"));
 
   /* Error if the connection has closed without a close_notify.
 
@@ -2039,7 +2055,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
       BACKEND->recv_sspi_close_notify = true;
     else {
       *err = CURLE_RECV_ERROR;
-      infof(data, "schannel: server closed abruptly (missing close_notify)\n");
+      infof(data, "schannel: server closed abruptly (missing close_notify)");
     }
   }
 
@@ -2053,9 +2069,9 @@ schannel_recv(struct Curl_easy *data, int sockindex,
     memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
             BACKEND->decdata_offset - size);
     BACKEND->decdata_offset -= size;
-    DEBUGF(infof(data, "schannel: decrypted data returned %zu\n", size));
+    DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
     DEBUGF(infof(data,
-                 "schannel: decrypted data buffer: offset %zu length %zu\n",
+                 "schannel: decrypted data buffer: offset %zu length %zu",
                  BACKEND->decdata_offset, BACKEND->decdata_length));
     *err = CURLE_OK;
     return (ssize_t)size;
@@ -2139,7 +2155,7 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
 
   DEBUGASSERT(data);
 
-  infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
+  infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu",
         hostname, conn->remote_port);
 
   if(BACKEND->cred && BACKEND->ctxt) {
@@ -2197,14 +2213,14 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
       s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
       if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
         infof(data, "schannel: failed to send close msg: %s"
-              " (bytes written: %zd)\n", curl_easy_strerror(result), written);
+              " (bytes written: %zd)", curl_easy_strerror(result), written);
       }
     }
   }
 
   /* free SSPI Schannel API security context handle */
   if(BACKEND->ctxt) {
-    DEBUGF(infof(data, "schannel: clear security context handle\n"));
+    DEBUGF(infof(data, "schannel: clear security context handle"));
     s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
     Curl_safefree(BACKEND->ctxt);
   }
index 25d47b8..1b283d0 100644 (file)
@@ -80,7 +80,7 @@ static int is_cr_or_lf(char c)
 /* Search the substring needle,needlelen into string haystack,haystacklen
  * Strings don't need to be terminated by a '\0'.
  * Similar of OSX/Linux memmem (not available on Visual Studio).
- * Return position of beginning of first occurence or NULL if not found
+ * Return position of beginning of first occurrence or NULL if not found
  */
 static const char *c_memmem(const void *haystack, size_t haystacklen,
                             const void *needle, size_t needlelen)
@@ -204,12 +204,12 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
   if(result == CURLE_OK) {
     if(!num_certs) {
       infof(data,
-            "schannel: did not add any certificates from CA file '%s'\n",
+            "schannel: did not add any certificates from CA file '%s'",
             ca_file_text);
     }
     else {
       infof(data,
-            "schannel: added %d certificate(s) from CA file '%s'\n",
+            "schannel: added %d certificate(s) from CA file '%s'",
             num_certs, ca_file_text);
     }
   }
@@ -526,7 +526,7 @@ static CURLcode verify_host(struct Curl_easy *data,
       if(match_result == CURL_HOST_MATCH) {
         infof(data,
               "schannel: connection hostname (%s) validated "
-              "against certificate name (%s)\n",
+              "against certificate name (%s)",
               conn_hostname, cert_hostname);
         result = CURLE_OK;
       }
@@ -535,7 +535,7 @@ static CURLcode verify_host(struct Curl_easy *data,
 
         infof(data,
               "schannel: connection hostname (%s) did not match "
-              "against certificate name (%s)\n",
+              "against certificate name (%s)",
               conn_hostname, cert_hostname);
 
         cert_hostname_len =
index edd375e..1e6ed5f 100644 (file)
@@ -32,6 +32,9 @@
 #include "curl_base64.h"
 #include "strtok.h"
 #include "multiif.h"
+#include "strcase.h"
+#include "x509asn1.h"
+#include "strerror.h"
 
 #ifdef USE_SECTRANSP
 
@@ -1644,7 +1647,7 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
     }
   }
   /* All cipher suites in the list are found. Report to logs as-is */
-  infof(data, "SSL: Setting cipher suites list \"%s\"\n", ciphers);
+  infof(data, "SSL: Setting cipher suites list \"%s\"", ciphers);
 
   err = SSLSetEnabledCiphers(ssl_ctx, selected_ciphers, ciphers_count);
   if(err != noErr) {
@@ -1840,19 +1843,19 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
 #endif
         ) {
         CFArrayAppendValue(alpnArr, CFSTR(ALPN_H2));
-        infof(data, "ALPN, offering %s\n", ALPN_H2);
+        infof(data, "ALPN, offering %s", ALPN_H2);
       }
 #endif
 
       CFArrayAppendValue(alpnArr, CFSTR(ALPN_HTTP_1_1));
-      infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+      infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
 
       /* expects length prefixed preference ordered list of protocols in wire
        * format
        */
       err = SSLSetALPNProtocols(backend->ssl_ctx, alpnArr);
       if(err != noErr)
-        infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d\n",
+        infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d",
               err);
       CFRelease(alpnArr);
     }
@@ -1861,7 +1864,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
 
   if(SSL_SET_OPTION(key)) {
     infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
-          "Transport. The private key must be in the Keychain.\n");
+          "Transport. The private key must be in the Keychain.");
   }
 
   if(ssl_cert || ssl_cert_blob) {
@@ -1869,24 +1872,28 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
     bool is_cert_file = (!is_cert_data) && is_file(ssl_cert);
     SecIdentityRef cert_and_key = NULL;
 
-    /* User wants to authenticate with a client cert. Look for it:
-       If we detect that this is a file on disk, then let's load it.
-       Otherwise, assume that the user wants to use an identity loaded
-       from the Keychain. */
-    if(is_cert_file || is_cert_data) {
+    /* User wants to authenticate with a client cert. Look for it. Assume that
+       the user wants to use an identity loaded from the Keychain. If not, try
+       it as a file on disk */
+
+    if(!is_cert_data)
+      err = CopyIdentityWithLabel(ssl_cert, &cert_and_key);
+    else
+      err = !noErr;
+    if((err != noErr) && (is_cert_file || is_cert_data)) {
       if(!SSL_SET_OPTION(cert_type))
-        infof(data, "WARNING: SSL: Certificate type not set, assuming "
-                    "PKCS#12 format.\n");
-      else if(strncmp(SSL_SET_OPTION(cert_type), "P12",
-        strlen(SSL_SET_OPTION(cert_type))) != 0)
-        infof(data, "WARNING: SSL: The Security framework only supports "
-                    "loading identities that are in PKCS#12 format.\n");
+        infof(data, "SSL: Certificate type not set, assuming "
+              "PKCS#12 format.");
+      else if(!strcasecompare(SSL_SET_OPTION(cert_type), "P12")) {
+        failf(data, "SSL: The Security framework only supports "
+              "loading identities that are in PKCS#12 format.");
+        return CURLE_SSL_CERTPROBLEM;
+      }
 
       err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob,
-        SSL_SET_OPTION(key_passwd), &cert_and_key);
+                                       SSL_SET_OPTION(key_passwd),
+                                       &cert_and_key);
     }
-    else
-      err = CopyIdentityWithLabel(ssl_cert, &cert_and_key);
 
     if(err == noErr && cert_and_key) {
       SecCertificateRef cert = NULL;
@@ -1899,7 +1906,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
         char *certp;
         CURLcode result = CopyCertSubject(data, cert, &certp);
         if(!result) {
-          infof(data, "Client certificate: %s\n", certp);
+          infof(data, "Client certificate: %s", certp);
           free(certp);
         }
 
@@ -2025,7 +2032,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
     strlen(hostname));
 
     if(err != noErr) {
-      infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n",
+      infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d",
             err);
     }
 
@@ -2035,11 +2042,11 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
   #endif
        ) {
       infof(data, "WARNING: using IP address, SNI is being disabled by "
-            "the OS.\n");
+            "the OS.");
     }
   }
   else {
-    infof(data, "WARNING: disabling hostname validation also disables SNI.\n");
+    infof(data, "WARNING: disabling hostname validation also disables SNI.");
   }
 
   ciphers = SSL_CONN_CONFIG(cipher_list);
@@ -2082,7 +2089,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
         return CURLE_SSL_CONNECT_ERROR;
       }
       /* Informational message */
-      infof(data, "SSL re-using session ID\n");
+      infof(data, "SSL re-using session ID");
     }
     /* If there isn't one, then let's make one up! This has to be done prior
        to starting the handshake. */
@@ -2487,7 +2494,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
         spkiHeaderLength = 23;
         break;
       default:
-        infof(data, "SSL: unhandled public key length: %d\n", pubkeylen);
+        infof(data, "SSL: unhandled public key length: %d", pubkeylen);
 #elif SECTRANSP_PINNEDPUBKEY_V2
       default:
         /* ecDSA secp256r1 pubkeylen == 91 header already included?
@@ -2778,35 +2785,35 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
     (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol);
     switch(protocol) {
       case kSSLProtocol2:
-        infof(data, "SSL 2.0 connection using %s\n",
+        infof(data, "SSL 2.0 connection using %s",
               TLSCipherNameForNumber(cipher));
         break;
       case kSSLProtocol3:
-        infof(data, "SSL 3.0 connection using %s\n",
+        infof(data, "SSL 3.0 connection using %s",
               TLSCipherNameForNumber(cipher));
         break;
       case kTLSProtocol1:
-        infof(data, "TLS 1.0 connection using %s\n",
+        infof(data, "TLS 1.0 connection using %s",
               TLSCipherNameForNumber(cipher));
         break;
 #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
       case kTLSProtocol11:
-        infof(data, "TLS 1.1 connection using %s\n",
+        infof(data, "TLS 1.1 connection using %s",
               TLSCipherNameForNumber(cipher));
         break;
       case kTLSProtocol12:
-        infof(data, "TLS 1.2 connection using %s\n",
+        infof(data, "TLS 1.2 connection using %s",
               TLSCipherNameForNumber(cipher));
         break;
 #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
 #if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
       case kTLSProtocol13:
-        infof(data, "TLS 1.3 connection using %s\n",
+        infof(data, "TLS 1.3 connection using %s",
               TLSCipherNameForNumber(cipher));
         break;
 #endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
       default:
-        infof(data, "Unknown protocol connection\n");
+        infof(data, "Unknown protocol connection");
         break;
     }
 
@@ -2832,7 +2839,7 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
           conn->negnpn = CURL_HTTP_VERSION_1_1;
         }
         else
-          infof(data, "ALPN, server did not agree to a protocol\n");
+          infof(data, "ALPN, server did not agree to a protocol");
 
         Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                             BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
@@ -2849,13 +2856,60 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
   }
 }
 
+static CURLcode
+add_cert_to_certinfo(struct Curl_easy *data,
+                     SecCertificateRef server_cert,
+                     int idx)
+{
+  CURLcode result = CURLE_OK;
+  const char *beg;
+  const char *end;
+  CFDataRef cert_data = SecCertificateCopyData(server_cert);
+
+  if(!cert_data)
+    return CURLE_PEER_FAILED_VERIFICATION;
+
+  beg = (const char *)CFDataGetBytePtr(cert_data);
+  end = beg + CFDataGetLength(cert_data);
+  result = Curl_extract_certinfo(data, idx, beg, end);
+  CFRelease(cert_data);
+  return result;
+}
+
+static CURLcode
+collect_server_cert_single(struct Curl_easy *data,
+                           SecCertificateRef server_cert,
+                           CFIndex idx)
+{
+  CURLcode result = CURLE_OK;
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
+  if(data->set.verbose) {
+    char *certp;
+    result = CopyCertSubject(data, server_cert, &certp);
+    if(!result) {
+      infof(data, "Server certificate: %s", certp);
+      free(certp);
+    }
+  }
+#endif
+  if(data->set.ssl.certinfo)
+    result = add_cert_to_certinfo(data, server_cert, (int)idx);
+  return result;
+}
+
 /* This should be called during step3 of the connection at the earliest */
-static void
-show_verbose_server_cert(struct Curl_easy *data,
-                         struct connectdata *conn,
-                         int sockindex)
+static CURLcode
+collect_server_cert(struct Curl_easy *data,
+                    struct connectdata *conn,
+                    int sockindex)
 {
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  const bool show_verbose_server_cert = data->set.verbose;
+#else
+  const bool show_verbose_server_cert = false;
+#endif
+  CURLcode result = data->set.ssl.certinfo ?
+    CURLE_PEER_FAILED_VERIFICATION : CURLE_OK;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   CFArrayRef server_certs = NULL;
@@ -2864,8 +2918,11 @@ show_verbose_server_cert(struct Curl_easy *data,
   CFIndex i, count;
   SecTrustRef trust = NULL;
 
+  if(!show_verbose_server_cert && !data->set.ssl.certinfo)
+    return CURLE_OK;
+
   if(!backend->ssl_ctx)
-    return;
+    return result;
 
 #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
 #if CURL_BUILD_IOS
@@ -2875,15 +2932,11 @@ show_verbose_server_cert(struct Curl_easy *data,
      a null trust, so be on guard for that: */
   if(err == noErr && trust) {
     count = SecTrustGetCertificateCount(trust);
-    for(i = 0L ; i < count ; i++) {
-      CURLcode result;
-      char *certp;
+    if(data->set.ssl.certinfo)
+      result = Curl_ssl_init_certinfo(data, (int)count);
+    for(i = 0L ; !result && (i < count) ; i++) {
       server_cert = SecTrustGetCertificateAtIndex(trust, i);
-      result = CopyCertSubject(data, server_cert, &certp);
-      if(!result) {
-        infof(data, "Server certificate: %s\n", certp);
-        free(certp);
-      }
+      result = collect_server_cert_single(data, server_cert, i);
     }
     CFRelease(trust);
   }
@@ -2901,15 +2954,11 @@ show_verbose_server_cert(struct Curl_easy *data,
        a null trust, so be on guard for that: */
     if(err == noErr && trust) {
       count = SecTrustGetCertificateCount(trust);
-      for(i = 0L ; i < count ; i++) {
-        char *certp;
-        CURLcode result;
+      if(data->set.ssl.certinfo)
+        result = Curl_ssl_init_certinfo(data, (int)count);
+      for(i = 0L ; !result && (i < count) ; i++) {
         server_cert = SecTrustGetCertificateAtIndex(trust, i);
-        result = CopyCertSubject(data, server_cert, &certp);
-        if(!result) {
-          infof(data, "Server certificate: %s\n", certp);
-          free(certp);
-        }
+        result = collect_server_cert_single(data, server_cert, i);
       }
       CFRelease(trust);
     }
@@ -2920,16 +2969,12 @@ show_verbose_server_cert(struct Curl_easy *data,
     /* Just in case SSLCopyPeerCertificates() returns null too... */
     if(err == noErr && server_certs) {
       count = CFArrayGetCount(server_certs);
-      for(i = 0L ; i < count ; i++) {
-        char *certp;
-        CURLcode result;
+      if(data->set.ssl.certinfo)
+        result = Curl_ssl_init_certinfo(data, (int)count);
+      for(i = 0L ; !result && (i < count) ; i++) {
         server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs,
                                                                 i);
-        result = CopyCertSubject(data, server_cert, &certp);
-        if(!result) {
-          infof(data, "Server certificate: %s\n", certp);
-          free(certp);
-        }
+        result = collect_server_cert_single(data, server_cert, i);
       }
       CFRelease(server_certs);
     }
@@ -2941,21 +2986,17 @@ show_verbose_server_cert(struct Curl_easy *data,
   err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs);
   if(err == noErr) {
     count = CFArrayGetCount(server_certs);
-    for(i = 0L ; i < count ; i++) {
-      CURLcode result;
-      char *certp;
+    if(data->set.ssl.certinfo)
+      result = Curl_ssl_init_certinfo(data, (int)count);
+    for(i = 0L ; !result && (i < count) ; i++) {
       server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i);
-      result = CopyCertSubject(data, server_cert, &certp);
-      if(!result) {
-        infof(data, "Server certificate: %s\n", certp);
-        free(certp);
-      }
+      result = collect_server_cert_single(data, server_cert, i);
     }
     CFRelease(server_certs);
   }
 #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
+  return result;
 }
-#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
 
 static CURLcode
 sectransp_connect_step3(struct Curl_easy *data, struct connectdata *conn,
@@ -2964,12 +3005,11 @@ sectransp_connect_step3(struct Curl_easy *data, struct connectdata *conn,
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
   /* There is no step 3!
-   * Well, okay, if verbose mode is on, let's print the details of the
-   * server certificates. */
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-  if(data->set.verbose)
-    show_verbose_server_cert(data, conn, sockindex);
-#endif
+   * Well, okay, let's collect server certificates, and if verbose mode is on,
+   * let's print the details of the server certificates. */
+  const CURLcode result = collect_server_cert(data, conn, sockindex);
+  if(result)
+    return result;
 
   connssl->connecting_state = ssl_connect_done;
   return CURLE_OK;
@@ -3148,6 +3188,7 @@ static int sectransp_shutdown(struct Curl_easy *data,
   int what;
   int rc;
   char buf[120];
+  int loop = 10; /* avoid getting stuck */
 
   if(!backend->ssl_ctx)
     return 0;
@@ -3163,7 +3204,7 @@ static int sectransp_shutdown(struct Curl_easy *data,
 
   what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT);
 
-  for(;;) {
+  while(loop--) {
     if(what < 0) {
       /* anything that gets here is fatally bad */
       failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -3182,7 +3223,9 @@ static int sectransp_shutdown(struct Curl_easy *data,
     nread = read(conn->sock[sockindex], buf, sizeof(buf));
 
     if(nread < 0) {
-      failf(data, "read: %s", strerror(errno));
+      char buffer[STRERROR_LEN];
+      failf(data, "read: %s",
+            Curl_strerror(errno, buffer, sizeof(buffer)));
       rc = -1;
     }
 
@@ -3427,6 +3470,7 @@ const struct Curl_ssl Curl_ssl_sectransp = {
   { CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */
 
   SSLSUPP_CAINFO_BLOB |
+  SSLSUPP_CERTINFO |
 #ifdef SECTRANSP_PINNEDPUBKEY
   SSLSUPP_PINNEDPUBKEY,
 #else
index 65f4f77..e5bbe1f 100644 (file)
@@ -125,6 +125,16 @@ static bool blobcmp(struct curl_blob *first, struct curl_blob *second)
   return !memcmp(first->data, second->data, first->len); /* same data */
 }
 
+static bool safecmp(char *a, char *b)
+{
+  if(a && b)
+    return !strcmp(a, b);
+  else if(!a && !b)
+    return TRUE; /* match */
+  return FALSE; /* no match */
+}
+
+
 bool
 Curl_ssl_config_matches(struct ssl_primary_config *data,
                         struct ssl_primary_config *needle)
@@ -136,11 +146,13 @@ Curl_ssl_config_matches(struct ssl_primary_config *data,
      (data->verifystatus == needle->verifystatus) &&
      blobcmp(data->cert_blob, needle->cert_blob) &&
      blobcmp(data->ca_info_blob, needle->ca_info_blob) &&
-     Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
-     Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
-     Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
-     Curl_safe_strcasecompare(data->random_file, needle->random_file) &&
-     Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) &&
+     blobcmp(data->issuercert_blob, needle->issuercert_blob) &&
+     safecmp(data->CApath, needle->CApath) &&
+     safecmp(data->CAfile, needle->CAfile) &&
+     safecmp(data->issuercert, needle->issuercert) &&
+     safecmp(data->clientcert, needle->clientcert) &&
+     safecmp(data->random_file, needle->random_file) &&
+     safecmp(data->egdsocket, needle->egdsocket) &&
      Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) &&
      Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) &&
      Curl_safe_strcasecompare(data->curves, needle->curves) &&
@@ -163,8 +175,10 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
 
   CLONE_BLOB(cert_blob);
   CLONE_BLOB(ca_info_blob);
+  CLONE_BLOB(issuercert_blob);
   CLONE_STRING(CApath);
   CLONE_STRING(CAfile);
+  CLONE_STRING(issuercert);
   CLONE_STRING(clientcert);
   CLONE_STRING(random_file);
   CLONE_STRING(egdsocket);
@@ -180,6 +194,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
 {
   Curl_safefree(sslc->CApath);
   Curl_safefree(sslc->CAfile);
+  Curl_safefree(sslc->issuercert);
   Curl_safefree(sslc->clientcert);
   Curl_safefree(sslc->random_file);
   Curl_safefree(sslc->egdsocket);
@@ -188,6 +203,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
   Curl_safefree(sslc->pinned_key);
   Curl_safefree(sslc->cert_blob);
   Curl_safefree(sslc->ca_info_blob);
+  Curl_safefree(sslc->issuercert_blob);
   Curl_safefree(sslc->curves);
 }
 
@@ -326,7 +342,7 @@ Curl_ssl_connect(struct Curl_easy *data, struct connectdata *conn,
 
 CURLcode
 Curl_ssl_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
-                             int sockindex, bool *done)
+                             bool isproxy, int sockindex, bool *done)
 {
   CURLcode result;
 
@@ -345,7 +361,7 @@ Curl_ssl_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
   result = Curl_ssl->connect_nonblocking(data, conn, sockindex, done);
   if(result)
     conn->ssl[sockindex].use = FALSE;
-  else if(*done)
+  else if(*done && !isproxy)
     Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */
   return result;
 }
@@ -407,8 +423,9 @@ bool Curl_ssl_getsessionid(struct Curl_easy *data,
 
   DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
 
-  if(!SSL_SET_OPTION(primary.sessionid))
-    /* session ID re-use is disabled */
+  if(!SSL_SET_OPTION(primary.sessionid) || !data->state.session)
+    /* session ID re-use is disabled or the session cache has not been
+       setup */
     return TRUE;
 
   /* Lock if shared */
@@ -443,6 +460,10 @@ bool Curl_ssl_getsessionid(struct Curl_easy *data,
     }
   }
 
+  DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
+               no_match? "Didn't find": "Found",
+               isProxy ? "proxy" : "host",
+               conn->handler->scheme, name, port));
   return no_match;
 }
 
@@ -492,14 +513,14 @@ void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
  */
 CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
                                struct connectdata *conn,
-                               bool isProxy,
+                               const bool isProxy,
                                void *ssl_sessionid,
                                size_t idsize,
                                int sockindex)
 {
   size_t i;
-  struct Curl_ssl_session *store = &data->state.session[0];
-  long oldest_age = data->state.session[0].age; /* zero if unused */
+  struct Curl_ssl_session *store;
+  long oldest_age;
   char *clone_host;
   char *clone_conn_to_host;
   int conn_to_port;
@@ -515,6 +536,11 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
   const char *hostname = conn->host.name;
 #endif
   (void)sockindex;
+  if(!data->state.session)
+    return CURLE_OK;
+
+  store = &data->state.session[0];
+  oldest_age = data->state.session[0].age; /* zero if unused */
   DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
 
   clone_host = strdup(hostname);
@@ -583,6 +609,9 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
     return CURLE_OUT_OF_MEMORY;
   }
 
+  DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
+               store->scheme, store->name, store->remote_port,
+               isProxy ? "PROXY" : "server"));
   return CURLE_OK;
 }
 
@@ -708,12 +737,12 @@ CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
 
 static size_t multissl_version(char *buffer, size_t size);
 
-size_t Curl_ssl_version(char *buffer, size_t size)
+void Curl_ssl_version(char *buffer, size_t size)
 {
 #ifdef CURL_WITH_MULTI_SSL
-  return multissl_version(buffer, size);
+  (void)multissl_version(buffer, size);
 #else
-  return Curl_ssl->version(buffer, size);
+  (void)Curl_ssl->version(buffer, size);
 #endif
 }
 
@@ -940,7 +969,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
     if(encode)
       return encode;
 
-    infof(data, "\t public key hash: sha256//%s\n", encoded);
+    infof(data, " public key hash: sha256//%s", encoded);
 
     /* it starts with sha256//, copy so we can modify it */
     pinkeylen = strlen(pinnedpubkey) + 1;
@@ -1374,7 +1403,7 @@ static int multissl_setup(const struct Curl_ssl *backend)
     for(i = 0; available_backends[i]; i++) {
       if(strcasecompare(env, available_backends[i]->info.name)) {
         Curl_ssl = available_backends[i];
-        curl_free(env_tmp);
+        free(env_tmp);
         return 0;
       }
     }
@@ -1382,7 +1411,7 @@ static int multissl_setup(const struct Curl_ssl *backend)
 
   /* Fall back to first available backend */
   Curl_ssl = available_backends[0];
-  curl_free(env_tmp);
+  free(env_tmp);
   return 0;
 }
 
index 7f93e7a..beaa83d 100644 (file)
@@ -193,6 +193,7 @@ CURLcode Curl_ssl_connect(struct Curl_easy *data, struct connectdata *conn,
                           int sockindex);
 CURLcode Curl_ssl_connect_nonblocking(struct Curl_easy *data,
                                       struct connectdata *conn,
+                                      bool isproxy,
                                       int sockindex,
                                       bool *done);
 /* tell the SSL stuff to close down all open information regarding
@@ -209,7 +210,7 @@ struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data);
 
 /* init the SSL session ID cache */
 CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t);
-size_t Curl_ssl_version(char *buffer, size_t size);
+void Curl_ssl_version(char *buffer, size_t size);
 bool Curl_ssl_data_pending(const struct connectdata *conn,
                            int connindex);
 int Curl_ssl_check_cxn(struct connectdata *conn);
@@ -246,7 +247,7 @@ void Curl_ssl_sessionid_unlock(struct Curl_easy *data);
  */
 bool Curl_ssl_getsessionid(struct Curl_easy *data,
                            struct connectdata *conn,
-                           const bool isproxy,
+                           const bool isProxy,
                            void **ssl_sessionid,
                            size_t *idsize, /* set 0 if unknown */
                            int sockindex);
@@ -313,7 +314,7 @@ void Curl_ssl_detach_conn(struct Curl_easy *data,
 #define Curl_ssl_data_pending(x,y) 0
 #define Curl_ssl_check_cxn(x) 0
 #define Curl_ssl_free_certinfo(x) Curl_nop_stmt
-#define Curl_ssl_connect_nonblocking(x,y,z,w) CURLE_NOT_BUILT_IN
+#define Curl_ssl_connect_nonblocking(x,y,z,w,a) CURLE_NOT_BUILT_IN
 #define Curl_ssl_kill_session(x) Curl_nop_stmt
 #define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
 #define Curl_ssl_cert_status_request() FALSE
index 60e27e3..16fbb89 100644 (file)
@@ -239,7 +239,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
     req_method = SSLv23_client_method();
 #else
     infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
-          "TLS 1.0 is used exclusively\n");
+          "TLS 1.0 is used exclusively");
     req_method = TLSv1_client_method();
 #endif
     use_sni(TRUE);
@@ -324,7 +324,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
       failf(data, "failed setting cipher list: %s", ciphers);
       return CURLE_SSL_CIPHER;
     }
-    infof(data, "Cipher selection: %s\n", ciphers);
+    infof(data, "Cipher selection: %s", ciphers);
   }
 
 #ifndef NO_FILESYSTEM
@@ -347,16 +347,16 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
         /* Just continue with a warning if no strict certificate
            verification is required. */
         infof(data, "error setting certificate verify locations,"
-              " continuing anyway:\n");
+              " continuing anyway:");
       }
     }
     else {
       /* Everything is fine. */
-      infof(data, "successfully set certificate verify locations:\n");
+      infof(data, "successfully set certificate verify locations:");
     }
-    infof(data, " CAfile: %s\n",
+    infof(data, " CAfile: %s",
           SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile) : "none");
-    infof(data, " CApath: %s\n",
+    infof(data, " CApath: %s",
           SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath) : "none");
   }
 
@@ -406,7 +406,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
        (wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, hostname,
                           (unsigned short)hostname_len) != 1)) {
       infof(data, "WARNING: failed to configure server name indication (SNI) "
-            "TLS extension\n");
+            "TLS extension");
     }
   }
 #endif
@@ -450,12 +450,12 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
 #ifdef USE_HTTP2
     if(data->state.httpwant >= CURL_HTTP_VERSION_2) {
       strcpy(protocols + strlen(protocols), ALPN_H2 ",");
-      infof(data, "ALPN, offering %s\n", ALPN_H2);
+      infof(data, "ALPN, offering %s", ALPN_H2);
     }
 #endif
 
     strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
-    infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+    infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
 
     if(wolfSSL_UseALPN(backend->handle, protocols,
                        (unsigned)strlen(protocols),
@@ -494,15 +494,11 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
                               &ssl_sessionid, NULL, sockindex)) {
       /* we got a session id, use it! */
       if(!SSL_set_session(backend->handle, ssl_sessionid)) {
-        char error_buffer[WOLFSSL_MAX_ERROR_SZ];
-        Curl_ssl_sessionid_unlock(data);
-        failf(data, "SSL: SSL_set_session failed: %s",
-              ERR_error_string(SSL_get_error(backend->handle, 0),
-                               error_buffer));
-        return CURLE_SSL_CONNECT_ERROR;
+        Curl_ssl_delsessionid(data, ssl_sessionid);
+        infof(data, "Can't use session ID, going on without\n");
       }
-      /* Informational message */
-      infof(data, "SSL re-using session ID\n");
+      else
+        infof(data, "SSL re-using session ID");
     }
     Curl_ssl_sessionid_unlock(data);
   }
@@ -529,6 +525,8 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
   const char * const dispname = SSL_HOST_DISPNAME();
   const char * const pinnedpubkey = SSL_PINNED_PUB_KEY();
 
+  ERR_clear_error();
+
   conn->recv[sockindex] = wolfssl_recv;
   conn->send[sockindex] = wolfssl_send;
 
@@ -582,7 +580,7 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
      * as also mismatching CN fields */
     else if(DOMAIN_NAME_MISMATCH == detail) {
 #if 1
-      failf(data, "\tsubject alt name(s) or common name do not match \"%s\"",
+      failf(data, " subject alt name(s) or common name do not match \"%s\"",
             dispname);
       return CURLE_PEER_FAILED_VERIFICATION;
 #else
@@ -594,13 +592,13 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
        * 'conn->ssl_config.verifyhost' value. */
       if(SSL_CONN_CONFIG(verifyhost)) {
         failf(data,
-              "\tsubject alt name(s) or common name do not match \"%s\"\n",
+              " subject alt name(s) or common name do not match \"%s\"\n",
               dispname);
         return CURLE_PEER_FAILED_VERIFICATION;
       }
       else {
         infof(data,
-              "\tsubject alt name(s) and/or common name do not match \"%s\"\n",
+              " subject alt name(s) and/or common name do not match \"%s\"",
               dispname);
         return CURLE_OK;
       }
@@ -609,14 +607,14 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
 #if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
     else if(ASN_NO_SIGNER_E == detail) {
       if(SSL_CONN_CONFIG(verifypeer)) {
-        failf(data, "\tCA signer not available for verification");
+        failf(data, " CA signer not available for verification");
         return CURLE_SSL_CACERT_BADFILE;
       }
       else {
         /* Just continue with a warning if no strict certificate
            verification is required. */
         infof(data, "CA signer not available for verification, "
-                    "continuing anyway\n");
+                    "continuing anyway");
       }
     }
 #endif
@@ -681,7 +679,7 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
     rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len);
 
     if(rc == SSL_SUCCESS) {
-      infof(data, "ALPN, server accepted to use %.*s\n", protocol_len,
+      infof(data, "ALPN, server accepted to use %.*s", protocol_len,
             protocol);
 
       if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
@@ -694,13 +692,13 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
         conn->negnpn = CURL_HTTP_VERSION_2;
 #endif
       else
-        infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len,
+        infof(data, "ALPN, unrecognized protocol %.*s", protocol_len,
               protocol);
       Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                           BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
     }
     else if(rc == SSL_ALPN_NOT_FOUND)
-      infof(data, "ALPN, server did not agree to a protocol\n");
+      infof(data, "ALPN, server did not agree to a protocol");
     else {
       failf(data, "ALPN, failure getting protocol, error %d", rc);
       return CURLE_SSL_CONNECT_ERROR;
@@ -710,11 +708,11 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
 
   connssl->connecting_state = ssl_connect_3;
 #if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
-  infof(data, "SSL connection using %s / %s\n",
+  infof(data, "SSL connection using %s / %s",
         wolfSSL_get_version(backend->handle),
         wolfSSL_get_cipher_name(backend->handle));
 #else
-  infof(data, "SSL connected\n");
+  infof(data, "SSL connected");
 #endif
 
   return CURLE_OK;
@@ -743,7 +741,7 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
                                         &old_ssl_sessionid, NULL, sockindex));
       if(incache) {
         if(old_ssl_sessionid != our_ssl_sessionid) {
-          infof(data, "old SSL session ID is stale, removing\n");
+          infof(data, "old SSL session ID is stale, removing");
           Curl_ssl_delsessionid(data, old_ssl_sessionid);
           incache = FALSE;
         }
@@ -779,7 +777,11 @@ static ssize_t wolfssl_send(struct Curl_easy *data,
   struct ssl_backend_data *backend = connssl->backend;
   char error_buffer[WOLFSSL_MAX_ERROR_SZ];
   int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
-  int rc = SSL_write(backend->handle, mem, memlen);
+  int rc;
+
+  ERR_clear_error();
+
+  rc = SSL_write(backend->handle, mem, memlen);
 
   if(rc <= 0) {
     int err = SSL_get_error(backend->handle, rc);
@@ -810,6 +812,10 @@ static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn,
   (void) data;
 
   if(backend->handle) {
+    char buf[32];
+    /* Maybe the server has already sent a close notify alert.
+       Read it to avoid an RST on the TCP connection. */
+    (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
     (void)SSL_shutdown(backend->handle);
     SSL_free(backend->handle);
     backend->handle = NULL;
@@ -831,7 +837,11 @@ static ssize_t wolfssl_recv(struct Curl_easy *data,
   struct ssl_backend_data *backend = connssl->backend;
   char error_buffer[WOLFSSL_MAX_ERROR_SZ];
   int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
-  int nread = SSL_read(backend->handle, buf, buffsize);
+  int nread;
+
+  ERR_clear_error();
+
+  nread = SSL_read(backend->handle, buf, buffsize);
 
   if(nread < 0) {
     int err = SSL_get_error(backend->handle, nread);
@@ -916,6 +926,7 @@ static int wolfssl_shutdown(struct Curl_easy *data, struct connectdata *conn,
   (void) data;
 
   if(backend->handle) {
+    ERR_clear_error();
     SSL_free(backend->handle);
     backend->handle = NULL;
   }
@@ -1089,7 +1100,7 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
 }
 
 static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
-                                        CURLINFO info UNUSED_PARAM)
+                                   CURLINFO info UNUSED_PARAM)
 {
   struct ssl_backend_data *backend = connssl->backend;
   (void)info;
index c0764c4..15c8156 100644 (file)
 
 #include "warnless.h"
 
-#define CURL_MASK_SCHAR  0x7F
-#define CURL_MASK_UCHAR  0xFF
-
-#if (SIZEOF_SHORT == 2)
-#  define CURL_MASK_SSHORT  0x7FFF
-#  define CURL_MASK_USHORT  0xFFFF
-#elif (SIZEOF_SHORT == 4)
-#  define CURL_MASK_SSHORT  0x7FFFFFFF
-#  define CURL_MASK_USHORT  0xFFFFFFFF
-#elif (SIZEOF_SHORT == 8)
-#  define CURL_MASK_SSHORT  0x7FFFFFFFFFFFFFFF
-#  define CURL_MASK_USHORT  0xFFFFFFFFFFFFFFFF
-#else
-#  error "SIZEOF_SHORT not defined"
-#endif
-
-#if (SIZEOF_INT == 2)
-#  define CURL_MASK_SINT  0x7FFF
-#  define CURL_MASK_UINT  0xFFFF
-#elif (SIZEOF_INT == 4)
-#  define CURL_MASK_SINT  0x7FFFFFFF
-#  define CURL_MASK_UINT  0xFFFFFFFF
-#elif (SIZEOF_INT == 8)
-#  define CURL_MASK_SINT  0x7FFFFFFFFFFFFFFF
-#  define CURL_MASK_UINT  0xFFFFFFFFFFFFFFFF
-#elif (SIZEOF_INT == 16)
-#  define CURL_MASK_SINT  0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
-#  define CURL_MASK_UINT  0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
-#else
-#  error "SIZEOF_INT not defined"
-#endif
-
-#if (SIZEOF_LONG == 2)
-#  define CURL_MASK_SLONG  0x7FFFL
-#  define CURL_MASK_ULONG  0xFFFFUL
-#elif (SIZEOF_LONG == 4)
-#  define CURL_MASK_SLONG  0x7FFFFFFFL
-#  define CURL_MASK_ULONG  0xFFFFFFFFUL
-#elif (SIZEOF_LONG == 8)
-#  define CURL_MASK_SLONG  0x7FFFFFFFFFFFFFFFL
-#  define CURL_MASK_ULONG  0xFFFFFFFFFFFFFFFFUL
-#elif (SIZEOF_LONG == 16)
-#  define CURL_MASK_SLONG  0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL
-#  define CURL_MASK_ULONG  0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFUL
-#else
-#  error "SIZEOF_LONG not defined"
-#endif
-
-#if (SIZEOF_CURL_OFF_T == 2)
-#  define CURL_MASK_SCOFFT  CURL_OFF_T_C(0x7FFF)
-#  define CURL_MASK_UCOFFT  CURL_OFF_TU_C(0xFFFF)
-#elif (SIZEOF_CURL_OFF_T == 4)
-#  define CURL_MASK_SCOFFT  CURL_OFF_T_C(0x7FFFFFFF)
-#  define CURL_MASK_UCOFFT  CURL_OFF_TU_C(0xFFFFFFFF)
-#elif (SIZEOF_CURL_OFF_T == 8)
-#  define CURL_MASK_SCOFFT  CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
-#  define CURL_MASK_UCOFFT  CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFF)
-#elif (SIZEOF_CURL_OFF_T == 16)
-#  define CURL_MASK_SCOFFT  CURL_OFF_T_C(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
-#  define CURL_MASK_UCOFFT  CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
-#else
-#  error "SIZEOF_CURL_OFF_T not defined"
-#endif
-
-#if (SIZEOF_SIZE_T == SIZEOF_SHORT)
-#  define CURL_MASK_SSIZE_T  CURL_MASK_SSHORT
-#  define CURL_MASK_USIZE_T  CURL_MASK_USHORT
-#elif (SIZEOF_SIZE_T == SIZEOF_INT)
-#  define CURL_MASK_SSIZE_T  CURL_MASK_SINT
-#  define CURL_MASK_USIZE_T  CURL_MASK_UINT
-#elif (SIZEOF_SIZE_T == SIZEOF_LONG)
-#  define CURL_MASK_SSIZE_T  CURL_MASK_SLONG
-#  define CURL_MASK_USIZE_T  CURL_MASK_ULONG
-#elif (SIZEOF_SIZE_T == SIZEOF_CURL_OFF_T)
-#  define CURL_MASK_SSIZE_T  CURL_MASK_SCOFFT
-#  define CURL_MASK_USIZE_T  CURL_MASK_UCOFFT
-#else
-#  error "SIZEOF_SIZE_T not defined"
-#endif
+#define CURL_MASK_UCHAR   ((unsigned char)~0)
+#define CURL_MASK_SCHAR   (CURL_MASK_UCHAR >> 1)
+
+#define CURL_MASK_USHORT  ((unsigned short)~0)
+#define CURL_MASK_SSHORT  (CURL_MASK_USHORT >> 1)
+
+#define CURL_MASK_UINT    ((unsigned int)~0)
+#define CURL_MASK_SINT    (CURL_MASK_UINT >> 1)
+
+#define CURL_MASK_ULONG   ((unsigned long)~0)
+#define CURL_MASK_SLONG   (CURL_MASK_ULONG >> 1)
+
+#define CURL_MASK_UCOFFT  ((unsigned CURL_TYPEOF_CURL_OFF_T)~0)
+#define CURL_MASK_SCOFFT  (CURL_MASK_UCOFFT >> 1)
+
+#define CURL_MASK_USIZE_T ((size_t)~0)
+#define CURL_MASK_SSIZE_T (CURL_MASK_USIZE_T >> 1)
 
 /*
 ** unsigned long to unsigned short
@@ -207,7 +145,7 @@ unsigned long curlx_uztoul(size_t uznum)
 # pragma warning(disable:810) /* conversion may lose significant bits */
 #endif
 
-#if (SIZEOF_LONG < SIZEOF_SIZE_T)
+#if ULONG_MAX < SIZE_T_MAX
   DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG);
 #endif
   return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG);
@@ -228,7 +166,7 @@ unsigned int curlx_uztoui(size_t uznum)
 # pragma warning(disable:810) /* conversion may lose significant bits */
 #endif
 
-#if (SIZEOF_INT < SIZEOF_SIZE_T)
+#if UINT_MAX < SIZE_T_MAX
   DEBUGASSERT(uznum <= (size_t) CURL_MASK_UINT);
 #endif
   return (unsigned int)(uznum & (size_t) CURL_MASK_UINT);
@@ -250,7 +188,7 @@ int curlx_sltosi(long slnum)
 #endif
 
   DEBUGASSERT(slnum >= 0);
-#if (SIZEOF_INT < SIZEOF_LONG)
+#if INT_MAX < LONG_MAX
   DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_SINT);
 #endif
   return (int)(slnum & (long) CURL_MASK_SINT);
@@ -272,7 +210,7 @@ unsigned int curlx_sltoui(long slnum)
 #endif
 
   DEBUGASSERT(slnum >= 0);
-#if (SIZEOF_INT < SIZEOF_LONG)
+#if UINT_MAX < LONG_MAX
   DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_UINT);
 #endif
   return (unsigned int)(slnum & (long) CURL_MASK_UINT);
@@ -352,7 +290,7 @@ int curlx_sztosi(ssize_t sznum)
 #endif
 
   DEBUGASSERT(sznum >= 0);
-#if (SIZEOF_INT < SIZEOF_SIZE_T)
+#if INT_MAX < SSIZE_T_MAX
   DEBUGASSERT((size_t) sznum <= (size_t) CURL_MASK_SINT);
 #endif
   return (int)(sznum & (ssize_t) CURL_MASK_SINT);
index 281c972..1bdaead 100644 (file)
@@ -23,7 +23,7 @@
 #include "curl_setup.h"
 
 #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
-    defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
+    defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
 
 #include <curl/curl.h>
 #include "urldata.h"
@@ -34,6 +34,7 @@
 #include "inet_pton.h"
 #include "curl_base64.h"
 #include "x509asn1.h"
+#include "dynbuf.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -205,16 +206,16 @@ static const char *bool2str(const char *beg, const char *end)
  */
 static const char *octet2str(const char *beg, const char *end)
 {
-  size_t n = end - beg;
-  char *buf = NULL;
+  struct dynbuf buf;
+  CURLcode result;
 
-  if(n <= (SIZE_T_MAX - 1) / 3) {
-    buf = malloc(3 * n + 1);
-    if(buf)
-      for(n = 0; beg < end; n += 3)
-        msnprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++);
-  }
-  return buf;
+  Curl_dyn_init(&buf, 3 * CURL_ASN1_MAX + 1);
+  result = Curl_dyn_addn(&buf, "", 0);
+
+  while(!result && beg < end)
+    result = Curl_dyn_addf(&buf, "%02x:", (unsigned char) *beg++);
+
+  return Curl_dyn_ptr(&buf);
 }
 
 static const char *bit2str(const char *beg, const char *end)
@@ -517,8 +518,8 @@ static const char *GTime2str(const char *beg, const char *end)
   return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
                        beg, beg + 4, beg + 6,
                        beg + 8, beg + 10, sec1, sec2,
-                       fracl? ".": "", fracl, fracp,
-                       sep, tzl, tzp);
+                       fracl? ".": "", (int)fracl, fracp,
+                       sep, (int)tzl, tzp);
 }
 
 /*
@@ -558,7 +559,7 @@ static const char *UTime2str(const char *beg, const char *end)
   return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
                        20 - (*beg >= '5'), beg, beg + 2, beg + 4,
                        beg + 6, beg + 8, sec,
-                       tzl, tzp);
+                       (int)tzl, tzp);
 }
 
 /*
@@ -866,7 +867,7 @@ static void do_pubkey_field(struct Curl_easy *data, int certnum,
     if(data->set.ssl.certinfo)
       Curl_ssl_push_certinfo(data, certnum, label, output);
     if(!certnum)
-      infof(data, "   %s: %s\n", label, output);
+      infof(data, "   %s: %s", label, output);
     free((char *) output);
   }
 }
@@ -905,7 +906,7 @@ static void do_pubkey(struct Curl_easy *data, int certnum,
     if(len > 32)
       elem.beg = q;     /* Strip leading zero bytes. */
     if(!certnum)
-      infof(data, "   RSA Public Key (%lu bits)\n", len);
+      infof(data, "   RSA Public Key (%lu bits)", len);
     if(data->set.ssl.certinfo) {
       q = curl_maprintf("%lu", len);
       if(q) {
@@ -978,7 +979,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
   if(data->set.ssl.certinfo)
     Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
   if(!certnum)
-    infof(data, "%2d Subject: %s\n", certnum, ccp);
+    infof(data, "%2d Subject: %s", certnum, ccp);
   free((char *) ccp);
 
   /* Issuer. */
@@ -988,7 +989,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
   if(data->set.ssl.certinfo)
     Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
   if(!certnum)
-    infof(data, "   Issuer: %s\n", ccp);
+    infof(data, "   Issuer: %s", ccp);
   free((char *) ccp);
 
   /* Version (always fits in less than 32 bits). */
@@ -1003,7 +1004,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
     free((char *) ccp);
   }
   if(!certnum)
-    infof(data, "   Version: %lu (0x%lx)\n", version + 1, version);
+    infof(data, "   Version: %lu (0x%lx)", version + 1, version);
 
   /* Serial number. */
   ccp = ASN1tostr(&cert.serialNumber, 0);
@@ -1012,7 +1013,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
   if(data->set.ssl.certinfo)
     Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
   if(!certnum)
-    infof(data, "   Serial Number: %s\n", ccp);
+    infof(data, "   Serial Number: %s", ccp);
   free((char *) ccp);
 
   /* Signature algorithm .*/
@@ -1023,7 +1024,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
   if(data->set.ssl.certinfo)
     Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
   if(!certnum)
-    infof(data, "   Signature Algorithm: %s\n", ccp);
+    infof(data, "   Signature Algorithm: %s", ccp);
   free((char *) ccp);
 
   /* Start Date. */
@@ -1033,7 +1034,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
   if(data->set.ssl.certinfo)
     Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
   if(!certnum)
-    infof(data, "   Start Date: %s\n", ccp);
+    infof(data, "   Start Date: %s", ccp);
   free((char *) ccp);
 
   /* Expire Date. */
@@ -1043,7 +1044,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
   if(data->set.ssl.certinfo)
     Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
   if(!certnum)
-    infof(data, "   Expire Date: %s\n", ccp);
+    infof(data, "   Expire Date: %s", ccp);
   free((char *) ccp);
 
   /* Public Key Algorithm. */
@@ -1054,7 +1055,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
   if(data->set.ssl.certinfo)
     Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
   if(!certnum)
-    infof(data, "   Public Key Algorithm: %s\n", ccp);
+    infof(data, "   Public Key Algorithm: %s", ccp);
   do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
   free((char *) ccp);
 
@@ -1065,7 +1066,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
   if(data->set.ssl.certinfo)
     Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
   if(!certnum)
-    infof(data, "   Signature: %s\n", ccp);
+    infof(data, "   Signature: %s", ccp);
   free((char *) ccp);
 
   /* Generate PEM certificate. */
@@ -1098,12 +1099,13 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
   if(data->set.ssl.certinfo)
     Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
   if(!certnum)
-    infof(data, "%s\n", cp2);
+    infof(data, "%s", cp2);
   free(cp2);
   return CURLE_OK;
 }
 
-#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL */
+#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL
+        * or USE_SECTRANSP */
 
 #if defined(USE_GSKIT)
 
@@ -1220,12 +1222,12 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
   switch(matched) {
   case 1:
     /* an alternative name matched the server hostname */
-    infof(data, "\t subjectAltName: %s matched\n", dispname);
+    infof(data, "  subjectAltName: %s matched", dispname);
     return CURLE_OK;
   case 0:
     /* an alternative name field existed, but didn't match and then
        we MUST fail */
-    infof(data, "\t subjectAltName does not match %s\n", dispname);
+    infof(data, "  subjectAltName does not match %s", dispname);
     return CURLE_PEER_FAILED_VERIFICATION;
   }
 
@@ -1262,7 +1264,7 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
     if(strlen(dnsname) != (size_t) len)         /* Nul byte in string ? */
       failf(data, "SSL: illegal cert name field");
     else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) {
-      infof(data, "\t common name: %s (matched)\n", dnsname);
+      infof(data, "  common name: %s (matched)", dnsname);
       free(dnsname);
       return CURLE_OK;
     }
index 326e32d..3b51eee 100644 (file)
@@ -26,7 +26,7 @@
 #include "curl_setup.h"
 
 #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
-    defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
+    defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
 
 #include "urldata.h"
 
@@ -129,5 +129,6 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, int certnum,
                                const char *beg, const char *end);
 CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
                          const char *beg, const char *end);
-#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL */
+#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL
+        * or USE_SECTRANSP */
 #endif /* HEADER_CURL_X509ASN1_H */
diff --git a/Utilities/cmelf/elf32.h b/Utilities/cmelf/elf32.h
new file mode 100644 (file)
index 0000000..20d2ec2
--- /dev/null
@@ -0,0 +1,265 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1996-1998 John D. Polstra.
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_ELF32_H_
+#define _SYS_ELF32_H_ 1
+
+#include "elf_common.h"
+
+/*
+ * ELF definitions common to all 32-bit architectures.
+ */
+
+typedef uint32_t       Elf32_Addr;
+typedef uint16_t       Elf32_Half;
+typedef uint32_t       Elf32_Off;
+typedef int32_t                Elf32_Sword;
+typedef uint32_t       Elf32_Word;
+typedef uint64_t       Elf32_Lword;
+
+typedef Elf32_Word     Elf32_Hashelt;
+
+/* Non-standard class-dependent datatype used for abstraction. */
+typedef Elf32_Word     Elf32_Size;
+typedef Elf32_Sword    Elf32_Ssize;
+
+/*
+ * ELF header.
+ */
+
+typedef struct {
+       unsigned char   e_ident[EI_NIDENT];     /* File identification. */
+       Elf32_Half      e_type;         /* File type. */
+       Elf32_Half      e_machine;      /* Machine architecture. */
+       Elf32_Word      e_version;      /* ELF format version. */
+       Elf32_Addr      e_entry;        /* Entry point. */
+       Elf32_Off       e_phoff;        /* Program header file offset. */
+       Elf32_Off       e_shoff;        /* Section header file offset. */
+       Elf32_Word      e_flags;        /* Architecture-specific flags. */
+       Elf32_Half      e_ehsize;       /* Size of ELF header in bytes. */
+       Elf32_Half      e_phentsize;    /* Size of program header entry. */
+       Elf32_Half      e_phnum;        /* Number of program header entries. */
+       Elf32_Half      e_shentsize;    /* Size of section header entry. */
+       Elf32_Half      e_shnum;        /* Number of section header entries. */
+       Elf32_Half      e_shstrndx;     /* Section name strings section. */
+} Elf32_Ehdr;
+
+/*
+ * Shared object information, found in SHT_MIPS_LIBLIST.
+ */
+
+typedef struct {
+       Elf32_Word l_name;              /* The name of a shared object. */
+       Elf32_Word l_time_stamp;        /* 32-bit timestamp. */
+       Elf32_Word l_checksum;          /* Checksum of visible symbols, sizes. */
+       Elf32_Word l_version;           /* Interface version string index. */
+       Elf32_Word l_flags;             /* Flags (LL_*). */
+} Elf32_Lib;
+
+/*
+ * Section header.
+ */
+
+typedef struct {
+       Elf32_Word      sh_name;        /* Section name (index into the
+                                          section header string table). */
+       Elf32_Word      sh_type;        /* Section type. */
+       Elf32_Word      sh_flags;       /* Section flags. */
+       Elf32_Addr      sh_addr;        /* Address in memory image. */
+       Elf32_Off       sh_offset;      /* Offset in file. */
+       Elf32_Word      sh_size;        /* Size in bytes. */
+       Elf32_Word      sh_link;        /* Index of a related section. */
+       Elf32_Word      sh_info;        /* Depends on section type. */
+       Elf32_Word      sh_addralign;   /* Alignment in bytes. */
+       Elf32_Word      sh_entsize;     /* Size of each entry in section. */
+} Elf32_Shdr;
+
+/*
+ * Program header.
+ */
+
+typedef struct {
+       Elf32_Word      p_type;         /* Entry type. */
+       Elf32_Off       p_offset;       /* File offset of contents. */
+       Elf32_Addr      p_vaddr;        /* Virtual address in memory image. */
+       Elf32_Addr      p_paddr;        /* Physical address (not used). */
+       Elf32_Word      p_filesz;       /* Size of contents in file. */
+       Elf32_Word      p_memsz;        /* Size of contents in memory. */
+       Elf32_Word      p_flags;        /* Access permission flags. */
+       Elf32_Word      p_align;        /* Alignment in memory and file. */
+} Elf32_Phdr;
+
+/*
+ * Dynamic structure.  The ".dynamic" section contains an array of them.
+ */
+
+typedef struct {
+       Elf32_Sword     d_tag;          /* Entry type. */
+       union {
+               Elf32_Word      d_val;  /* Integer value. */
+               Elf32_Addr      d_ptr;  /* Address value. */
+       } d_un;
+} Elf32_Dyn;
+
+/*
+ * Relocation entries.
+ */
+
+/* Relocations that don't need an addend field. */
+typedef struct {
+       Elf32_Addr      r_offset;       /* Location to be relocated. */
+       Elf32_Word      r_info;         /* Relocation type and symbol index. */
+} Elf32_Rel;
+
+/* Relocations that need an addend field. */
+typedef struct {
+       Elf32_Addr      r_offset;       /* Location to be relocated. */
+       Elf32_Word      r_info;         /* Relocation type and symbol index. */
+       Elf32_Sword     r_addend;       /* Addend. */
+} Elf32_Rela;
+
+/* Macros for accessing the fields of r_info. */
+#define ELF32_R_SYM(info)      ((info) >> 8)
+#define ELF32_R_TYPE(info)     ((unsigned char)(info))
+
+/* Macro for constructing r_info from field values. */
+#define ELF32_R_INFO(sym, type)        (((sym) << 8) + (unsigned char)(type))
+
+/*
+ *     Note entry header
+ */
+typedef Elf_Note Elf32_Nhdr;
+
+/*
+ *     Move entry
+ */
+typedef struct {
+       Elf32_Lword     m_value;        /* symbol value */
+       Elf32_Word      m_info;         /* size + index */
+       Elf32_Word      m_poffset;      /* symbol offset */
+       Elf32_Half      m_repeat;       /* repeat count */
+       Elf32_Half      m_stride;       /* stride info */
+} Elf32_Move;
+
+/*
+ *     The macros compose and decompose values for Move.r_info
+ *
+ *     sym = ELF32_M_SYM(M.m_info)
+ *     size = ELF32_M_SIZE(M.m_info)
+ *     M.m_info = ELF32_M_INFO(sym, size)
+ */
+#define        ELF32_M_SYM(info)       ((info)>>8)
+#define        ELF32_M_SIZE(info)      ((unsigned char)(info))
+#define        ELF32_M_INFO(sym, size) (((sym)<<8)+(unsigned char)(size))
+
+/*
+ *     Hardware/Software capabilities entry
+ */
+typedef struct {
+       Elf32_Word      c_tag;          /* how to interpret value */
+       union {
+               Elf32_Word      c_val;
+               Elf32_Addr      c_ptr;
+       } c_un;
+} Elf32_Cap;
+
+/*
+ * Symbol table entries.
+ */
+
+typedef struct {
+       Elf32_Word      st_name;        /* String table index of name. */
+       Elf32_Addr      st_value;       /* Symbol value. */
+       Elf32_Word      st_size;        /* Size of associated object. */
+       unsigned char   st_info;        /* Type and binding information. */
+       unsigned char   st_other;       /* Reserved (not used). */
+       Elf32_Half      st_shndx;       /* Section index of symbol. */
+} Elf32_Sym;
+
+/* Macros for accessing the fields of st_info. */
+#define ELF32_ST_BIND(info)            ((info) >> 4)
+#define ELF32_ST_TYPE(info)            ((info) & 0xf)
+
+/* Macro for constructing st_info from field values. */
+#define ELF32_ST_INFO(bind, type)      (((bind) << 4) + ((type) & 0xf))
+
+/* Macro for accessing the fields of st_other. */
+#define ELF32_ST_VISIBILITY(oth)       ((oth) & 0x3)
+
+/* Structures used by Sun & GNU symbol versioning. */
+typedef struct
+{
+       Elf32_Half      vd_version;
+       Elf32_Half      vd_flags;
+       Elf32_Half      vd_ndx;
+       Elf32_Half      vd_cnt;
+       Elf32_Word      vd_hash;
+       Elf32_Word      vd_aux;
+       Elf32_Word      vd_next;
+} Elf32_Verdef;
+
+typedef struct
+{
+       Elf32_Word      vda_name;
+       Elf32_Word      vda_next;
+} Elf32_Verdaux;
+
+typedef struct
+{
+       Elf32_Half      vn_version;
+       Elf32_Half      vn_cnt;
+       Elf32_Word      vn_file;
+       Elf32_Word      vn_aux;
+       Elf32_Word      vn_next;
+} Elf32_Verneed;
+
+typedef struct
+{
+       Elf32_Word      vna_hash;
+       Elf32_Half      vna_flags;
+       Elf32_Half      vna_other;
+       Elf32_Word      vna_name;
+       Elf32_Word      vna_next;
+} Elf32_Vernaux;
+
+typedef Elf32_Half Elf32_Versym;
+
+typedef struct {
+       Elf32_Half      si_boundto;     /* direct bindings - symbol bound to */
+       Elf32_Half      si_flags;       /* per symbol flags */
+} Elf32_Syminfo;
+
+typedef struct {
+       Elf32_Word      ch_type;
+       Elf32_Word      ch_size;
+       Elf32_Word      ch_addralign;
+} Elf32_Chdr;
+
+#endif /* !_SYS_ELF32_H_ */
diff --git a/Utilities/cmelf/elf64.h b/Utilities/cmelf/elf64.h
new file mode 100644 (file)
index 0000000..6efe147
--- /dev/null
@@ -0,0 +1,269 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 1996-1998 John D. Polstra.
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_ELF64_H_
+#define _SYS_ELF64_H_ 1
+
+#include "elf_common.h"
+
+/*
+ * ELF definitions common to all 64-bit architectures.
+ */
+
+typedef uint64_t       Elf64_Addr;
+typedef uint16_t       Elf64_Half;
+typedef uint64_t       Elf64_Off;
+typedef int32_t                Elf64_Sword;
+typedef int64_t                Elf64_Sxword;
+typedef uint32_t       Elf64_Word;
+typedef uint64_t       Elf64_Lword;
+typedef uint64_t       Elf64_Xword;
+
+/*
+ * Types of dynamic symbol hash table bucket and chain elements.
+ *
+ * This is inconsistent among 64 bit architectures, so a machine dependent
+ * typedef is required.
+ */
+
+typedef Elf64_Word     Elf64_Hashelt;
+
+/* Non-standard class-dependent datatype used for abstraction. */
+typedef Elf64_Xword    Elf64_Size;
+typedef Elf64_Sxword   Elf64_Ssize;
+
+/*
+ * ELF header.
+ */
+
+typedef struct {
+       unsigned char   e_ident[EI_NIDENT];     /* File identification. */
+       Elf64_Half      e_type;         /* File type. */
+       Elf64_Half      e_machine;      /* Machine architecture. */
+       Elf64_Word      e_version;      /* ELF format version. */
+       Elf64_Addr      e_entry;        /* Entry point. */
+       Elf64_Off       e_phoff;        /* Program header file offset. */
+       Elf64_Off       e_shoff;        /* Section header file offset. */
+       Elf64_Word      e_flags;        /* Architecture-specific flags. */
+       Elf64_Half      e_ehsize;       /* Size of ELF header in bytes. */
+       Elf64_Half      e_phentsize;    /* Size of program header entry. */
+       Elf64_Half      e_phnum;        /* Number of program header entries. */
+       Elf64_Half      e_shentsize;    /* Size of section header entry. */
+       Elf64_Half      e_shnum;        /* Number of section header entries. */
+       Elf64_Half      e_shstrndx;     /* Section name strings section. */
+} Elf64_Ehdr;
+
+/*
+ * Shared object information, found in SHT_MIPS_LIBLIST.
+ */
+
+typedef struct {
+       Elf64_Word l_name;              /* The name of a shared object. */
+       Elf64_Word l_time_stamp;        /* 64-bit timestamp. */
+       Elf64_Word l_checksum;          /* Checksum of visible symbols, sizes. */
+       Elf64_Word l_version;           /* Interface version string index. */
+       Elf64_Word l_flags;             /* Flags (LL_*). */
+} Elf64_Lib;
+
+/*
+ * Section header.
+ */
+
+typedef struct {
+       Elf64_Word      sh_name;        /* Section name (index into the
+                                          section header string table). */
+       Elf64_Word      sh_type;        /* Section type. */
+       Elf64_Xword     sh_flags;       /* Section flags. */
+       Elf64_Addr      sh_addr;        /* Address in memory image. */
+       Elf64_Off       sh_offset;      /* Offset in file. */
+       Elf64_Xword     sh_size;        /* Size in bytes. */
+       Elf64_Word      sh_link;        /* Index of a related section. */
+       Elf64_Word      sh_info;        /* Depends on section type. */
+       Elf64_Xword     sh_addralign;   /* Alignment in bytes. */
+       Elf64_Xword     sh_entsize;     /* Size of each entry in section. */
+} Elf64_Shdr;
+
+/*
+ * Program header.
+ */
+
+typedef struct {
+       Elf64_Word      p_type;         /* Entry type. */
+       Elf64_Word      p_flags;        /* Access permission flags. */
+       Elf64_Off       p_offset;       /* File offset of contents. */
+       Elf64_Addr      p_vaddr;        /* Virtual address in memory image. */
+       Elf64_Addr      p_paddr;        /* Physical address (not used). */
+       Elf64_Xword     p_filesz;       /* Size of contents in file. */
+       Elf64_Xword     p_memsz;        /* Size of contents in memory. */
+       Elf64_Xword     p_align;        /* Alignment in memory and file. */
+} Elf64_Phdr;
+
+/*
+ * Dynamic structure.  The ".dynamic" section contains an array of them.
+ */
+
+typedef struct {
+       Elf64_Sxword    d_tag;          /* Entry type. */
+       union {
+               Elf64_Xword     d_val;  /* Integer value. */
+               Elf64_Addr      d_ptr;  /* Address value. */
+       } d_un;
+} Elf64_Dyn;
+
+/*
+ * Relocation entries.
+ */
+
+/* Relocations that don't need an addend field. */
+typedef struct {
+       Elf64_Addr      r_offset;       /* Location to be relocated. */
+       Elf64_Xword     r_info;         /* Relocation type and symbol index. */
+} Elf64_Rel;
+
+/* Relocations that need an addend field. */
+typedef struct {
+       Elf64_Addr      r_offset;       /* Location to be relocated. */
+       Elf64_Xword     r_info;         /* Relocation type and symbol index. */
+       Elf64_Sxword    r_addend;       /* Addend. */
+} Elf64_Rela;
+
+/* Macros for accessing the fields of r_info. */
+#define        ELF64_R_SYM(info)       ((info) >> 32)
+#define        ELF64_R_TYPE(info)      ((info) & 0xffffffffL)
+
+/* Macro for constructing r_info from field values. */
+#define        ELF64_R_INFO(sym, type) (((sym) << 32) + ((type) & 0xffffffffL))
+
+#define        ELF64_R_TYPE_DATA(info) (((Elf64_Xword)(info)<<32)>>40)
+#define        ELF64_R_TYPE_ID(info)   (((Elf64_Xword)(info)<<56)>>56)
+#define        ELF64_R_TYPE_INFO(data, type)   \
+                               (((Elf64_Xword)(data)<<8)+(Elf64_Xword)(type))
+
+/*
+ *     Note entry header
+ */
+typedef Elf_Note Elf64_Nhdr;
+
+/*
+ *     Move entry
+ */
+typedef struct {
+       Elf64_Lword     m_value;        /* symbol value */
+       Elf64_Xword     m_info;         /* size + index */
+       Elf64_Xword     m_poffset;      /* symbol offset */
+       Elf64_Half      m_repeat;       /* repeat count */
+       Elf64_Half      m_stride;       /* stride info */
+} Elf64_Move;
+
+#define        ELF64_M_SYM(info)       ((info)>>8)
+#define        ELF64_M_SIZE(info)      ((unsigned char)(info))
+#define        ELF64_M_INFO(sym, size) (((sym)<<8)+(unsigned char)(size))
+
+/*
+ *     Hardware/Software capabilities entry
+ */
+typedef struct {
+       Elf64_Xword     c_tag;          /* how to interpret value */
+       union {
+               Elf64_Xword     c_val;
+               Elf64_Addr      c_ptr;
+       } c_un;
+} Elf64_Cap;
+
+/*
+ * Symbol table entries.
+ */
+
+typedef struct {
+       Elf64_Word      st_name;        /* String table index of name. */
+       unsigned char   st_info;        /* Type and binding information. */
+       unsigned char   st_other;       /* Reserved (not used). */
+       Elf64_Half      st_shndx;       /* Section index of symbol. */
+       Elf64_Addr      st_value;       /* Symbol value. */
+       Elf64_Xword     st_size;        /* Size of associated object. */
+} Elf64_Sym;
+
+/* Macros for accessing the fields of st_info. */
+#define        ELF64_ST_BIND(info)             ((info) >> 4)
+#define        ELF64_ST_TYPE(info)             ((info) & 0xf)
+
+/* Macro for constructing st_info from field values. */
+#define        ELF64_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
+
+/* Macro for accessing the fields of st_other. */
+#define        ELF64_ST_VISIBILITY(oth)        ((oth) & 0x3)
+
+/* Structures used by Sun & GNU-style symbol versioning. */
+typedef struct {
+       Elf64_Half      vd_version;
+       Elf64_Half      vd_flags;
+       Elf64_Half      vd_ndx;
+       Elf64_Half      vd_cnt;
+       Elf64_Word      vd_hash;
+       Elf64_Word      vd_aux;
+       Elf64_Word      vd_next;
+} Elf64_Verdef;
+
+typedef struct {
+       Elf64_Word      vda_name;
+       Elf64_Word      vda_next;
+} Elf64_Verdaux;
+
+typedef struct {
+       Elf64_Half      vn_version;
+       Elf64_Half      vn_cnt;
+       Elf64_Word      vn_file;
+       Elf64_Word      vn_aux;
+       Elf64_Word      vn_next;
+} Elf64_Verneed;
+
+typedef struct {
+       Elf64_Word      vna_hash;
+       Elf64_Half      vna_flags;
+       Elf64_Half      vna_other;
+       Elf64_Word      vna_name;
+       Elf64_Word      vna_next;
+} Elf64_Vernaux;
+
+typedef Elf64_Half Elf64_Versym;
+
+typedef struct {
+       Elf64_Half      si_boundto;     /* direct bindings - symbol bound to */
+       Elf64_Half      si_flags;       /* per symbol flags */
+} Elf64_Syminfo;
+
+typedef struct {
+       Elf64_Word      ch_type;
+       Elf64_Word      ch_reserved;
+       Elf64_Xword     ch_size;
+       Elf64_Xword     ch_addralign;
+} Elf64_Chdr;
+
+#endif /* !_SYS_ELF64_H_ */
diff --git a/Utilities/cmelf/elf_common.h b/Utilities/cmelf/elf_common.h
new file mode 100644 (file)
index 0000000..395c45b
--- /dev/null
@@ -0,0 +1,1492 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2017, 2018 Dell EMC
+ * Copyright (c) 2000, 2001, 2008, 2011, David E. O'Brien
+ * Copyright (c) 1998 John D. Polstra.
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_ELF_COMMON_H_
+#define        _SYS_ELF_COMMON_H_ 1
+
+/*
+ * ELF definitions that are independent of architecture or word size.
+ */
+
+/*
+ * Note header.  The ".note" section contains an array of notes.  Each
+ * begins with this header, aligned to a word boundary.  Immediately
+ * following the note header is n_namesz bytes of name, padded to the
+ * next word boundary.  Then comes n_descsz bytes of descriptor, again
+ * padded to a word boundary.  The values of n_namesz and n_descsz do
+ * not include the padding.
+ */
+
+#ifndef LOCORE
+typedef struct {
+       uint32_t        n_namesz;       /* Length of name. */
+       uint32_t        n_descsz;       /* Length of descriptor. */
+       uint32_t        n_type;         /* Type of this note. */
+} Elf_Note;
+typedef Elf_Note Elf_Nhdr;
+#endif
+
+/*
+ * Option kinds.
+ */
+#define        ODK_NULL        0       /* undefined */
+#define        ODK_REGINFO     1       /* register usage info */
+#define        ODK_EXCEPTIONS  2       /* exception processing info */
+#define        ODK_PAD         3       /* section padding */
+#define        ODK_HWPATCH     4       /* hardware patch applied */
+#define        ODK_FILL        5       /* fill value used by the linker */
+#define        ODK_TAGS        6       /* reserved space for tools */
+#define        ODK_HWAND       7       /* hardware AND patch applied */
+#define        ODK_HWOR        8       /* hardware OR patch applied */
+#define        ODK_GP_GROUP    9       /* GP group for text/data sections */
+#define        ODK_IDENT       10      /* ID information */
+#define        ODK_PAGESIZE    11      /* page size information */
+
+/*
+ * ODK_EXCEPTIONS info field masks.
+ */
+#define        OEX_FPU_MIN     0x0000001f      /* min FPU exception required */
+#define        OEX_FPU_MAX     0x00001f00      /* max FPU exception allowed */
+#define        OEX_PAGE0       0x00010000      /* page zero must be mapped */
+#define        OEX_SMM         0x00020000      /* run in sequential memory mode */
+#define        OEX_PRECISEFP   0x00040000      /* run in precise FP exception mode */
+#define        OEX_DISMISS     0x00080000      /* dismiss invalid address traps */
+
+/*
+ * ODK_PAD info field masks.
+ */
+#define        OPAD_PREFIX     0x0001
+#define        OPAD_POSTFIX    0x0002
+#define        OPAD_SYMBOL     0x0004
+
+/*
+ * ODK_HWPATCH info field masks.
+ */
+#define        OHW_R4KEOP      0x00000001      /* patch for R4000 branch at end-of-page bug */
+#define        OHW_R8KPFETCH   0x00000002      /* R8000 prefetch bug may occur */
+#define        OHW_R5KEOP      0x00000004      /* patch for R5000 branch at end-of-page bug */
+#define        OHW_R5KCVTL     0x00000008      /* R5000 cvt.[ds].l bug: clean == 1 */
+#define        OHW_R10KLDL     0x00000010UL    /* need patch for R10000 misaligned load */
+
+/*
+ * ODK_HWAND/ODK_HWOR info field and hwp_flags[12] masks.
+ */
+#define        OHWA0_R4KEOP_CHECKED    0x00000001      /* object checked for R4000 end-of-page bug */
+#define        OHWA0_R4KEOP_CLEAN      0x00000002      /* object verified clean for R4000 end-of-page bug */
+#define        OHWO0_FIXADE            0x00000001      /* object requires call to fixade */
+
+/*
+ * ODK_IDENT/ODK_GP_GROUP info field masks.
+ */
+#define        OGP_GROUP       0x0000ffff      /* GP group number */
+#define        OGP_SELF        0x00010000      /* GP group is self-contained */
+
+/*
+ * The header for GNU-style hash sections.
+ */
+
+#ifndef LOCORE
+typedef struct {
+       uint32_t        gh_nbuckets;    /* Number of hash buckets. */
+       uint32_t        gh_symndx;      /* First visible symbol in .dynsym. */
+       uint32_t        gh_maskwords;   /* #maskwords used in bloom filter. */
+       uint32_t        gh_shift2;      /* Bloom filter shift count. */
+} Elf_GNU_Hash_Header;
+#endif
+
+/* Indexes into the e_ident array.  Keep synced with
+   http://www.sco.com/developers/gabi/latest/ch4.eheader.html */
+#define        EI_MAG0         0       /* Magic number, byte 0. */
+#define        EI_MAG1         1       /* Magic number, byte 1. */
+#define        EI_MAG2         2       /* Magic number, byte 2. */
+#define        EI_MAG3         3       /* Magic number, byte 3. */
+#define        EI_CLASS        4       /* Class of machine. */
+#define        EI_DATA         5       /* Data format. */
+#define        EI_VERSION      6       /* ELF format version. */
+#define        EI_OSABI        7       /* Operating system / ABI identification */
+#define        EI_ABIVERSION   8       /* ABI version */
+#define        OLD_EI_BRAND    8       /* Start of architecture identification. */
+#define        EI_PAD          9       /* Start of padding (per SVR4 ABI). */
+#define        EI_NIDENT       16      /* Size of e_ident array. */
+
+/* Values for the magic number bytes. */
+#define        ELFMAG0         0x7f
+#define        ELFMAG1         'E'
+#define        ELFMAG2         'L'
+#define        ELFMAG3         'F'
+#define        ELFMAG          "\177ELF"       /* magic string */
+#define        SELFMAG         4               /* magic string size */
+
+/* Values for e_ident[EI_VERSION] and e_version. */
+#define        EV_NONE         0
+#define        EV_CURRENT      1
+
+/* Values for e_ident[EI_CLASS]. */
+#define        ELFCLASSNONE    0       /* Unknown class. */
+#define        ELFCLASS32      1       /* 32-bit architecture. */
+#define        ELFCLASS64      2       /* 64-bit architecture. */
+
+/* Values for e_ident[EI_DATA]. */
+#define        ELFDATANONE     0       /* Unknown data format. */
+#define        ELFDATA2LSB     1       /* 2's complement little-endian. */
+#define        ELFDATA2MSB     2       /* 2's complement big-endian. */
+
+/* Values for e_ident[EI_OSABI]. */
+#define        ELFOSABI_NONE           0       /* UNIX System V ABI */
+#define        ELFOSABI_HPUX           1       /* HP-UX operating system */
+#define        ELFOSABI_NETBSD         2       /* NetBSD */
+#define        ELFOSABI_LINUX          3       /* GNU/Linux */
+#define        ELFOSABI_HURD           4       /* GNU/Hurd */
+#define        ELFOSABI_86OPEN         5       /* 86Open common IA32 ABI */
+#define        ELFOSABI_SOLARIS        6       /* Solaris */
+#define        ELFOSABI_AIX            7       /* AIX */
+#define        ELFOSABI_IRIX           8       /* IRIX */
+#define        ELFOSABI_FREEBSD        9       /* FreeBSD */
+#define        ELFOSABI_TRU64          10      /* TRU64 UNIX */
+#define        ELFOSABI_MODESTO        11      /* Novell Modesto */
+#define        ELFOSABI_OPENBSD        12      /* OpenBSD */
+#define        ELFOSABI_OPENVMS        13      /* Open VMS */
+#define        ELFOSABI_NSK            14      /* HP Non-Stop Kernel */
+#define        ELFOSABI_AROS           15      /* Amiga Research OS */
+#define        ELFOSABI_FENIXOS        16      /* FenixOS */
+#define        ELFOSABI_CLOUDABI       17      /* Nuxi CloudABI */
+#define        ELFOSABI_OPENVOS        18      /* Stratus Technologies OpenVOS */
+#define        ELFOSABI_ARM_AEABI      64      /* ARM EABI */
+#define        ELFOSABI_ARM            97      /* ARM */
+#define        ELFOSABI_STANDALONE     255     /* Standalone (embedded) application */
+
+#define        ELFOSABI_SYSV           ELFOSABI_NONE   /* symbol used in old spec */
+#define        ELFOSABI_MONTEREY       ELFOSABI_AIX    /* Monterey */
+#define        ELFOSABI_GNU            ELFOSABI_LINUX
+
+/* e_ident */
+#define        IS_ELF(ehdr)    ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
+                        (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
+                        (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
+                        (ehdr).e_ident[EI_MAG3] == ELFMAG3)
+
+/* Values for e_type. */
+#define        ET_NONE         0       /* Unknown type. */
+#define        ET_REL          1       /* Relocatable. */
+#define        ET_EXEC         2       /* Executable. */
+#define        ET_DYN          3       /* Shared object. */
+#define        ET_CORE         4       /* Core file. */
+#define        ET_LOOS         0xfe00  /* First operating system specific. */
+#define        ET_HIOS         0xfeff  /* Last operating system-specific. */
+#define        ET_LOPROC       0xff00  /* First processor-specific. */
+#define        ET_HIPROC       0xffff  /* Last processor-specific. */
+
+/* Values for e_machine. */
+#define        EM_NONE         0       /* Unknown machine. */
+#define        EM_M32          1       /* AT&T WE32100. */
+#define        EM_SPARC        2       /* Sun SPARC. */
+#define        EM_386          3       /* Intel i386. */
+#define        EM_68K          4       /* Motorola 68000. */
+#define        EM_88K          5       /* Motorola 88000. */
+#define        EM_IAMCU        6       /* Intel MCU. */
+#define        EM_860          7       /* Intel i860. */
+#define        EM_MIPS         8       /* MIPS R3000 Big-Endian only. */
+#define        EM_S370         9       /* IBM System/370. */
+#define        EM_MIPS_RS3_LE  10      /* MIPS R3000 Little-Endian. */
+#define        EM_PARISC       15      /* HP PA-RISC. */
+#define        EM_VPP500       17      /* Fujitsu VPP500. */
+#define        EM_SPARC32PLUS  18      /* SPARC v8plus. */
+#define        EM_960          19      /* Intel 80960. */
+#define        EM_PPC          20      /* PowerPC 32-bit. */
+#define        EM_PPC64        21      /* PowerPC 64-bit. */
+#define        EM_S390         22      /* IBM System/390. */
+#define        EM_V800         36      /* NEC V800. */
+#define        EM_FR20         37      /* Fujitsu FR20. */
+#define        EM_RH32         38      /* TRW RH-32. */
+#define        EM_RCE          39      /* Motorola RCE. */
+#define        EM_ARM          40      /* ARM. */
+#define        EM_SH           42      /* Hitachi SH. */
+#define        EM_SPARCV9      43      /* SPARC v9 64-bit. */
+#define        EM_TRICORE      44      /* Siemens TriCore embedded processor. */
+#define        EM_ARC          45      /* Argonaut RISC Core. */
+#define        EM_H8_300       46      /* Hitachi H8/300. */
+#define        EM_H8_300H      47      /* Hitachi H8/300H. */
+#define        EM_H8S          48      /* Hitachi H8S. */
+#define        EM_H8_500       49      /* Hitachi H8/500. */
+#define        EM_IA_64        50      /* Intel IA-64 Processor. */
+#define        EM_MIPS_X       51      /* Stanford MIPS-X. */
+#define        EM_COLDFIRE     52      /* Motorola ColdFire. */
+#define        EM_68HC12       53      /* Motorola M68HC12. */
+#define        EM_MMA          54      /* Fujitsu MMA. */
+#define        EM_PCP          55      /* Siemens PCP. */
+#define        EM_NCPU         56      /* Sony nCPU. */
+#define        EM_NDR1         57      /* Denso NDR1 microprocessor. */
+#define        EM_STARCORE     58      /* Motorola Star*Core processor. */
+#define        EM_ME16         59      /* Toyota ME16 processor. */
+#define        EM_ST100        60      /* STMicroelectronics ST100 processor. */
+#define        EM_TINYJ        61      /* Advanced Logic Corp. TinyJ processor. */
+#define        EM_X86_64       62      /* Advanced Micro Devices x86-64 */
+#define        EM_AMD64        EM_X86_64       /* Advanced Micro Devices x86-64 (compat) */
+#define        EM_PDSP         63      /* Sony DSP Processor. */
+#define        EM_FX66         66      /* Siemens FX66 microcontroller. */
+#define        EM_ST9PLUS      67      /* STMicroelectronics ST9+ 8/16
+                                  microcontroller. */
+#define        EM_ST7          68      /* STmicroelectronics ST7 8-bit
+                                  microcontroller. */
+#define        EM_68HC16       69      /* Motorola MC68HC16 microcontroller. */
+#define        EM_68HC11       70      /* Motorola MC68HC11 microcontroller. */
+#define        EM_68HC08       71      /* Motorola MC68HC08 microcontroller. */
+#define        EM_68HC05       72      /* Motorola MC68HC05 microcontroller. */
+#define        EM_SVX          73      /* Silicon Graphics SVx. */
+#define        EM_ST19         74      /* STMicroelectronics ST19 8-bit mc. */
+#define        EM_VAX          75      /* Digital VAX. */
+#define        EM_CRIS         76      /* Axis Communications 32-bit embedded
+                                  processor. */
+#define        EM_JAVELIN      77      /* Infineon Technologies 32-bit embedded
+                                  processor. */
+#define        EM_FIREPATH     78      /* Element 14 64-bit DSP Processor. */
+#define        EM_ZSP          79      /* LSI Logic 16-bit DSP Processor. */
+#define        EM_MMIX         80      /* Donald Knuth's educational 64-bit proc. */
+#define        EM_HUANY        81      /* Harvard University machine-independent
+                                  object files. */
+#define        EM_PRISM        82      /* SiTera Prism. */
+#define        EM_AVR          83      /* Atmel AVR 8-bit microcontroller. */
+#define        EM_FR30         84      /* Fujitsu FR30. */
+#define        EM_D10V         85      /* Mitsubishi D10V. */
+#define        EM_D30V         86      /* Mitsubishi D30V. */
+#define        EM_V850         87      /* NEC v850. */
+#define        EM_M32R         88      /* Mitsubishi M32R. */
+#define        EM_MN10300      89      /* Matsushita MN10300. */
+#define        EM_MN10200      90      /* Matsushita MN10200. */
+#define        EM_PJ           91      /* picoJava. */
+#define        EM_OPENRISC     92      /* OpenRISC 32-bit embedded processor. */
+#define        EM_ARC_A5       93      /* ARC Cores Tangent-A5. */
+#define        EM_XTENSA       94      /* Tensilica Xtensa Architecture. */
+#define        EM_VIDEOCORE    95      /* Alphamosaic VideoCore processor. */
+#define        EM_TMM_GPP      96      /* Thompson Multimedia General Purpose
+                                  Processor. */
+#define        EM_NS32K        97      /* National Semiconductor 32000 series. */
+#define        EM_TPC          98      /* Tenor Network TPC processor. */
+#define        EM_SNP1K        99      /* Trebia SNP 1000 processor. */
+#define        EM_ST200        100     /* STMicroelectronics ST200 microcontroller. */
+#define        EM_IP2K         101     /* Ubicom IP2xxx microcontroller family. */
+#define        EM_MAX          102     /* MAX Processor. */
+#define        EM_CR           103     /* National Semiconductor CompactRISC
+                                  microprocessor. */
+#define        EM_F2MC16       104     /* Fujitsu F2MC16. */
+#define        EM_MSP430       105     /* Texas Instruments embedded microcontroller
+                                  msp430. */
+#define        EM_BLACKFIN     106     /* Analog Devices Blackfin (DSP) processor. */
+#define        EM_SE_C33       107     /* S1C33 Family of Seiko Epson processors. */
+#define        EM_SEP          108     /* Sharp embedded microprocessor. */
+#define        EM_ARCA         109     /* Arca RISC Microprocessor. */
+#define        EM_UNICORE      110     /* Microprocessor series from PKU-Unity Ltd.
+                                  and MPRC of Peking University */
+#define        EM_AARCH64      183     /* AArch64 (64-bit ARM) */
+#define        EM_RISCV        243     /* RISC-V */
+
+/* Non-standard or deprecated. */
+#define        EM_486          6       /* Intel i486. */
+#define        EM_MIPS_RS4_BE  10      /* MIPS R4000 Big-Endian */
+#define        EM_ALPHA_STD    41      /* Digital Alpha (standard value). */
+#define        EM_ALPHA        0x9026  /* Alpha (written in the absence of an ABI) */
+
+/**
+ * e_flags
+ */
+#define        EF_ARM_RELEXEC  0x1
+#define        EF_ARM_HASENTRY 0x2
+#define        EF_ARM_SYMSARESORTED    0x4
+#define        EF_ARM_DYNSYMSUSESEGIDX 0x8
+#define        EF_ARM_MAPSYMSFIRST     0x10
+#define        EF_ARM_LE8              0x00400000
+#define        EF_ARM_BE8              0x00800000
+#define        EF_ARM_EABIMASK         0xFF000000
+#define        EF_ARM_EABI_UNKNOWN     0x00000000
+#define        EF_ARM_EABI_VER1        0x01000000
+#define        EF_ARM_EABI_VER2        0x02000000
+#define        EF_ARM_EABI_VER3        0x03000000
+#define        EF_ARM_EABI_VER4        0x04000000
+#define        EF_ARM_EABI_VER5        0x05000000
+#define        EF_ARM_INTERWORK        0x00000004
+#define        EF_ARM_APCS_26          0x00000008
+#define        EF_ARM_APCS_FLOAT       0x00000010
+#define        EF_ARM_PIC              0x00000020
+#define        EF_ARM_ALIGN8           0x00000040
+#define        EF_ARM_NEW_ABI          0x00000080
+#define        EF_ARM_OLD_ABI          0x00000100
+#define        EF_ARM_ABI_FLOAT_SOFT   0x00000200
+#define        EF_ARM_SOFT_FLOAT       EF_ARM_ABI_FLOAT_SOFT /* Pre-V5 ABI name */
+#define        EF_ARM_ABI_FLOAT_HARD   0x00000400
+#define        EF_ARM_VFP_FLOAT        EF_ARM_ABI_FLOAT_HARD /* Pre-V5 ABI name */
+#define        EF_ARM_MAVERICK_FLOAT   0x00000800
+
+#define        EF_MIPS_NOREORDER       0x00000001
+#define        EF_MIPS_PIC             0x00000002      /* Contains PIC code */
+#define        EF_MIPS_CPIC            0x00000004      /* STD PIC calling sequence */
+#define        EF_MIPS_UCODE           0x00000010
+#define        EF_MIPS_ABI2            0x00000020      /* N32 */
+#define        EF_MIPS_OPTIONS_FIRST   0x00000080
+#define        EF_MIPS_ABI             0x0000F000
+#define        EF_MIPS_ABI_O32         0x00001000
+#define        EF_MIPS_ABI_O64         0x00002000
+#define        EF_MIPS_ABI_EABI32      0x00003000
+#define        EF_MIPS_ABI_EABI64      0x00004000
+#define        EF_MIPS_ARCH_ASE        0x0F000000      /* Architectural extensions */
+#define        EF_MIPS_ARCH_ASE_MDMX   0x08000000      /* MDMX multimedia extension */
+#define        EF_MIPS_ARCH_ASE_M16    0x04000000      /* MIPS-16 ISA extensions */
+#define        EF_MIPS_ARCH            0xF0000000      /* Architecture field */
+#define        EF_MIPS_ARCH_1          0x00000000      /* -mips1 code */
+#define        EF_MIPS_ARCH_2          0x10000000      /* -mips2 code */
+#define        EF_MIPS_ARCH_3          0x20000000      /* -mips3 code */
+#define        EF_MIPS_ARCH_4          0x30000000      /* -mips4 code */
+#define        EF_MIPS_ARCH_5          0x40000000      /* -mips5 code */
+#define        EF_MIPS_ARCH_32         0x50000000      /* -mips32 code */
+#define        EF_MIPS_ARCH_64         0x60000000      /* -mips64 code */
+#define        EF_MIPS_ARCH_32R2       0x70000000      /* -mips32r2 code */
+#define        EF_MIPS_ARCH_64R2       0x80000000      /* -mips64r2 code */
+
+#define        EF_PPC_EMB              0x80000000
+#define        EF_PPC_RELOCATABLE      0x00010000
+#define        EF_PPC_RELOCATABLE_LIB  0x00008000
+
+#define        EF_RISCV_RVC            0x00000001
+#define        EF_RISCV_FLOAT_ABI_MASK 0x00000006
+#define        EF_RISCV_FLOAT_ABI_SOFT 0x00000000
+#define        EF_RISCV_FLOAT_ABI_SINGLE 0x000002
+#define        EF_RISCV_FLOAT_ABI_DOUBLE 0x000004
+#define        EF_RISCV_FLOAT_ABI_QUAD 0x00000006
+#define        EF_RISCV_RVE            0x00000008
+#define        EF_RISCV_TSO            0x00000010
+
+#define        EF_SPARC_EXT_MASK       0x00ffff00
+#define        EF_SPARC_32PLUS         0x00000100
+#define        EF_SPARC_SUN_US1        0x00000200
+#define        EF_SPARC_HAL_R1         0x00000200
+#define        EF_SPARC_SUN_US3        0x00000800
+
+#define        EF_SPARCV9_MM           0x00000003
+#define        EF_SPARCV9_TSO          0x00000000
+#define        EF_SPARCV9_PSO          0x00000001
+#define        EF_SPARCV9_RMO          0x00000002
+
+/* Special section indexes. */
+#define        SHN_UNDEF            0          /* Undefined, missing, irrelevant. */
+#define        SHN_LORESERVE   0xff00          /* First of reserved range. */
+#define        SHN_LOPROC      0xff00          /* First processor-specific. */
+#define        SHN_HIPROC      0xff1f          /* Last processor-specific. */
+#define        SHN_LOOS        0xff20          /* First operating system-specific. */
+#define        SHN_FBSD_CACHED SHN_LOOS        /* Transient, for sys/kern/link_elf_obj
+                                          linker only: Cached global in local
+                                          symtab. */
+#define        SHN_HIOS        0xff3f          /* Last operating system-specific. */
+#define        SHN_ABS         0xfff1          /* Absolute values. */
+#define        SHN_COMMON      0xfff2          /* Common data. */
+#define        SHN_XINDEX      0xffff          /* Escape -- index stored elsewhere. */
+#define        SHN_HIRESERVE   0xffff          /* Last of reserved range. */
+
+/* sh_type */
+#define        SHT_NULL                0       /* inactive */
+#define        SHT_PROGBITS            1       /* program defined information */
+#define        SHT_SYMTAB              2       /* symbol table section */
+#define        SHT_STRTAB              3       /* string table section */
+#define        SHT_RELA                4       /* relocation section with addends */
+#define        SHT_HASH                5       /* symbol hash table section */
+#define        SHT_DYNAMIC             6       /* dynamic section */
+#define        SHT_NOTE                7       /* note section */
+#define        SHT_NOBITS              8       /* no space section */
+#define        SHT_REL                 9       /* relocation section - no addends */
+#define        SHT_SHLIB               10      /* reserved - purpose unknown */
+#define        SHT_DYNSYM              11      /* dynamic symbol table section */
+#define        SHT_INIT_ARRAY          14      /* Initialization function pointers. */
+#define        SHT_FINI_ARRAY          15      /* Termination function pointers. */
+#define        SHT_PREINIT_ARRAY       16      /* Pre-initialization function ptrs. */
+#define        SHT_GROUP               17      /* Section group. */
+#define        SHT_SYMTAB_SHNDX        18      /* Section indexes (see SHN_XINDEX). */
+#define        SHT_LOOS                0x60000000      /* First of OS specific semantics */
+#define        SHT_LOSUNW              0x6ffffff4
+#define        SHT_SUNW_dof            0x6ffffff4
+#define        SHT_SUNW_cap            0x6ffffff5
+#define        SHT_GNU_ATTRIBUTES      0x6ffffff5
+#define        SHT_SUNW_SIGNATURE      0x6ffffff6
+#define        SHT_GNU_HASH            0x6ffffff6
+#define        SHT_GNU_LIBLIST         0x6ffffff7
+#define        SHT_SUNW_ANNOTATE       0x6ffffff7
+#define        SHT_SUNW_DEBUGSTR       0x6ffffff8
+#define        SHT_SUNW_DEBUG          0x6ffffff9
+#define        SHT_SUNW_move           0x6ffffffa
+#define        SHT_SUNW_COMDAT         0x6ffffffb
+#define        SHT_SUNW_syminfo        0x6ffffffc
+#define        SHT_SUNW_verdef         0x6ffffffd
+#define        SHT_GNU_verdef          0x6ffffffd      /* Symbol versions provided */
+#define        SHT_SUNW_verneed        0x6ffffffe
+#define        SHT_GNU_verneed         0x6ffffffe      /* Symbol versions required */
+#define        SHT_SUNW_versym         0x6fffffff
+#define        SHT_GNU_versym          0x6fffffff      /* Symbol version table */
+#define        SHT_HISUNW              0x6fffffff
+#define        SHT_HIOS                0x6fffffff      /* Last of OS specific semantics */
+#define        SHT_LOPROC              0x70000000      /* reserved range for processor */
+#define        SHT_X86_64_UNWIND       0x70000001      /* unwind information */
+#define        SHT_AMD64_UNWIND        SHT_X86_64_UNWIND 
+
+#define        SHT_ARM_EXIDX           0x70000001      /* Exception index table. */
+#define        SHT_ARM_PREEMPTMAP      0x70000002      /* BPABI DLL dynamic linking 
+                                                  pre-emption map. */
+#define        SHT_ARM_ATTRIBUTES      0x70000003      /* Object file compatibility 
+                                                  attributes. */
+#define        SHT_ARM_DEBUGOVERLAY    0x70000004      /* See DBGOVL for details. */
+#define        SHT_ARM_OVERLAYSECTION  0x70000005      /* See DBGOVL for details. */
+#define        SHT_MIPS_LIBLIST        0x70000000
+#define        SHT_MIPS_MSYM           0x70000001
+#define        SHT_MIPS_CONFLICT       0x70000002
+#define        SHT_MIPS_GPTAB          0x70000003
+#define        SHT_MIPS_UCODE          0x70000004
+#define        SHT_MIPS_DEBUG          0x70000005
+#define        SHT_MIPS_REGINFO        0x70000006
+#define        SHT_MIPS_PACKAGE        0x70000007
+#define        SHT_MIPS_PACKSYM        0x70000008
+#define        SHT_MIPS_RELD           0x70000009
+#define        SHT_MIPS_IFACE          0x7000000b
+#define        SHT_MIPS_CONTENT        0x7000000c
+#define        SHT_MIPS_OPTIONS        0x7000000d
+#define        SHT_MIPS_DELTASYM       0x7000001b
+#define        SHT_MIPS_DELTAINST      0x7000001c
+#define        SHT_MIPS_DELTACLASS     0x7000001d
+#define        SHT_MIPS_DWARF          0x7000001e      /* MIPS gcc uses MIPS_DWARF */
+#define        SHT_MIPS_DELTADECL      0x7000001f
+#define        SHT_MIPS_SYMBOL_LIB     0x70000020
+#define        SHT_MIPS_EVENTS         0x70000021
+#define        SHT_MIPS_TRANSLATE      0x70000022
+#define        SHT_MIPS_PIXIE          0x70000023
+#define        SHT_MIPS_XLATE          0x70000024
+#define        SHT_MIPS_XLATE_DEBUG    0x70000025
+#define        SHT_MIPS_WHIRL          0x70000026
+#define        SHT_MIPS_EH_REGION      0x70000027
+#define        SHT_MIPS_XLATE_OLD      0x70000028
+#define        SHT_MIPS_PDR_EXCEPTION  0x70000029
+#define        SHT_MIPS_ABIFLAGS       0x7000002a
+
+#define        SHT_SPARC_GOTDATA       0x70000000
+
+#define        SHTORDERED
+#define        SHT_HIPROC              0x7fffffff      /* specific section header types */
+#define        SHT_LOUSER              0x80000000      /* reserved range for application */
+#define        SHT_HIUSER              0xffffffff      /* specific indexes */
+
+/* Flags for sh_flags. */
+#define        SHF_WRITE               0x1     /* Section contains writable data. */
+#define        SHF_ALLOC               0x2     /* Section occupies memory. */
+#define        SHF_EXECINSTR           0x4     /* Section contains instructions. */
+#define        SHF_MERGE               0x10    /* Section may be merged. */
+#define        SHF_STRINGS             0x20    /* Section contains strings. */
+#define        SHF_INFO_LINK           0x40    /* sh_info holds section index. */
+#define        SHF_LINK_ORDER          0x80    /* Special ordering requirements. */
+#define        SHF_OS_NONCONFORMING    0x100   /* OS-specific processing required. */
+#define        SHF_GROUP               0x200   /* Member of section group. */
+#define        SHF_TLS                 0x400   /* Section contains TLS data. */
+#define        SHF_COMPRESSED          0x800   /* Section contains compressed data. */
+#define        SHF_MASKOS      0x0ff00000      /* OS-specific semantics. */
+#define        SHF_MASKPROC    0xf0000000      /* Processor-specific semantics. */
+
+/* Flags for section groups. */
+#define        GRP_COMDAT      0x1     /* COMDAT semantics. */
+
+/*
+ * Flags / mask for .gnu.versym sections.
+ */
+#define        VERSYM_VERSION  0x7fff
+#define        VERSYM_HIDDEN   0x8000
+
+/* Values for p_type. */
+#define        PT_NULL         0       /* Unused entry. */
+#define        PT_LOAD         1       /* Loadable segment. */
+#define        PT_DYNAMIC      2       /* Dynamic linking information segment. */
+#define        PT_INTERP       3       /* Pathname of interpreter. */
+#define        PT_NOTE         4       /* Auxiliary information. */
+#define        PT_SHLIB        5       /* Reserved (not used). */
+#define        PT_PHDR         6       /* Location of program header itself. */
+#define        PT_TLS          7       /* Thread local storage segment */
+#define        PT_LOOS         0x60000000      /* First OS-specific. */
+#define        PT_SUNW_UNWIND  0x6464e550      /* amd64 UNWIND program header */
+#define        PT_GNU_EH_FRAME 0x6474e550
+#define        PT_GNU_STACK    0x6474e551
+#define        PT_GNU_RELRO    0x6474e552
+#define        PT_DUMP_DELTA   0x6fb5d000      /* va->pa map for kernel dumps
+                                          (currently arm). */
+#define        PT_LOSUNW       0x6ffffffa
+#define        PT_SUNWBSS      0x6ffffffa      /* Sun Specific segment */
+#define        PT_SUNWSTACK    0x6ffffffb      /* describes the stack segment */
+#define        PT_SUNWDTRACE   0x6ffffffc      /* private */
+#define        PT_SUNWCAP      0x6ffffffd      /* hard/soft capabilities segment */
+#define        PT_HISUNW       0x6fffffff
+#define        PT_HIOS         0x6fffffff      /* Last OS-specific. */
+#define        PT_LOPROC       0x70000000      /* First processor-specific type. */
+#define        PT_ARM_ARCHEXT  0x70000000      /* ARM arch compat information. */
+#define        PT_ARM_EXIDX    0x70000001      /* ARM exception unwind tables. */
+#define        PT_MIPS_REGINFO         0x70000000      /* MIPS register usage info */
+#define        PT_MIPS_RTPROC          0x70000001      /* MIPS runtime procedure tbl */
+#define        PT_MIPS_OPTIONS         0x70000002      /* MIPS e_flags value*/
+#define        PT_MIPS_ABIFLAGS        0x70000003      /* MIPS fp mode */
+#define        PT_HIPROC       0x7fffffff      /* Last processor-specific type. */
+
+#define        PT_OPENBSD_RANDOMIZE    0x65A3DBE6      /* OpenBSD random data segment */
+#define        PT_OPENBSD_WXNEEDED     0x65A3DBE7      /* OpenBSD EXEC/WRITE pages needed */
+#define        PT_OPENBSD_BOOTDATA     0x65A41BE6      /* OpenBSD section for boot args */
+
+/* Values for p_flags. */
+#define        PF_X            0x1             /* Executable. */
+#define        PF_W            0x2             /* Writable. */
+#define        PF_R            0x4             /* Readable. */
+#define        PF_MASKOS       0x0ff00000      /* Operating system-specific. */
+#define        PF_MASKPROC     0xf0000000      /* Processor-specific. */
+
+/* Extended program header index. */
+#define        PN_XNUM         0xffff
+
+/* Values for d_tag. */
+#define        DT_NULL         0       /* Terminating entry. */
+#define        DT_NEEDED       1       /* String table offset of a needed shared
+                                  library. */
+#define        DT_PLTRELSZ     2       /* Total size in bytes of PLT relocations. */
+#define        DT_PLTGOT       3       /* Processor-dependent address. */
+#define        DT_HASH         4       /* Address of symbol hash table. */
+#define        DT_STRTAB       5       /* Address of string table. */
+#define        DT_SYMTAB       6       /* Address of symbol table. */
+#define        DT_RELA         7       /* Address of ElfNN_Rela relocations. */
+#define        DT_RELASZ       8       /* Total size of ElfNN_Rela relocations. */
+#define        DT_RELAENT      9       /* Size of each ElfNN_Rela relocation entry. */
+#define        DT_STRSZ        10      /* Size of string table. */
+#define        DT_SYMENT       11      /* Size of each symbol table entry. */
+#define        DT_INIT         12      /* Address of initialization function. */
+#define        DT_FINI         13      /* Address of finalization function. */
+#define        DT_SONAME       14      /* String table offset of shared object
+                                  name. */
+#define        DT_RPATH        15      /* String table offset of library path. [sup] */
+#define        DT_SYMBOLIC     16      /* Indicates "symbolic" linking. [sup] */
+#define        DT_REL          17      /* Address of ElfNN_Rel relocations. */
+#define        DT_RELSZ        18      /* Total size of ElfNN_Rel relocations. */
+#define        DT_RELENT       19      /* Size of each ElfNN_Rel relocation. */
+#define        DT_PLTREL       20      /* Type of relocation used for PLT. */
+#define        DT_DEBUG        21      /* Reserved (not used). */
+#define        DT_TEXTREL      22      /* Indicates there may be relocations in
+                                  non-writable segments. [sup] */
+#define        DT_JMPREL       23      /* Address of PLT relocations. */
+#define        DT_BIND_NOW     24      /* [sup] */
+#define        DT_INIT_ARRAY   25      /* Address of the array of pointers to
+                                  initialization functions */
+#define        DT_FINI_ARRAY   26      /* Address of the array of pointers to
+                                  termination functions */
+#define        DT_INIT_ARRAYSZ 27      /* Size in bytes of the array of
+                                  initialization functions. */
+#define        DT_FINI_ARRAYSZ 28      /* Size in bytes of the array of
+                                  termination functions. */
+#define        DT_RUNPATH      29      /* String table offset of a null-terminated
+                                  library search path string. */
+#define        DT_FLAGS        30      /* Object specific flag values. */
+#define        DT_ENCODING     32      /* Values greater than or equal to DT_ENCODING
+                                  and less than DT_LOOS follow the rules for
+                                  the interpretation of the d_un union
+                                  as follows: even == 'd_ptr', odd == 'd_val'
+                                  or none */
+#define        DT_PREINIT_ARRAY 32     /* Address of the array of pointers to
+                                  pre-initialization functions. */
+#define        DT_PREINIT_ARRAYSZ 33   /* Size in bytes of the array of
+                                  pre-initialization functions. */
+#define        DT_MAXPOSTAGS   34      /* number of positive tags */
+#define        DT_LOOS         0x6000000d      /* First OS-specific */
+#define        DT_SUNW_AUXILIARY       0x6000000d      /* symbol auxiliary name */
+#define        DT_SUNW_RTLDINF         0x6000000e      /* ld.so.1 info (private) */
+#define        DT_SUNW_FILTER          0x6000000f      /* symbol filter name */
+#define        DT_SUNW_CAP             0x60000010      /* hardware/software */
+#define        DT_SUNW_ASLR            0x60000023      /* ASLR control */
+#define        DT_HIOS         0x6ffff000      /* Last OS-specific */
+
+/*
+ * DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
+ * Dyn.d_un.d_val field of the Elf*_Dyn structure.
+ */
+#define        DT_VALRNGLO     0x6ffffd00
+#define        DT_GNU_PRELINKED        0x6ffffdf5 /* prelinking timestamp */
+#define        DT_GNU_CONFLICTSZ       0x6ffffdf6 /* size of conflict section */
+#define        DT_GNU_LIBLISTSZ        0x6ffffdf7 /* size of library list */
+#define        DT_CHECKSUM     0x6ffffdf8      /* elf checksum */
+#define        DT_PLTPADSZ     0x6ffffdf9      /* pltpadding size */
+#define        DT_MOVEENT      0x6ffffdfa      /* move table entry size */
+#define        DT_MOVESZ       0x6ffffdfb      /* move table size */
+#define        DT_FEATURE      0x6ffffdfc      /* feature holder */
+#define        DT_FEATURE_1    DT_FEATURE
+#define        DT_POSFLAG_1    0x6ffffdfd      /* flags for DT_* entries, effecting */
+                                       /*      the following DT_* entry. */
+                                       /*      See DF_P1_* definitions */
+#define        DT_SYMINSZ      0x6ffffdfe      /* syminfo table size (in bytes) */
+#define        DT_SYMINENT     0x6ffffdff      /* syminfo entry size (in bytes) */
+#define        DT_VALRNGHI     0x6ffffdff
+
+/*
+ * DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
+ * Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
+ *
+ * If any adjustment is made to the ELF object after it has been
+ * built, these entries will need to be adjusted.
+ */
+#define        DT_ADDRRNGLO    0x6ffffe00
+#define        DT_GNU_HASH     0x6ffffef5      /* GNU-style hash table */
+#define        DT_TLSDESC_PLT  0x6ffffef6      /* loc. of PLT for tlsdesc resolver */
+#define        DT_TLSDESC_GOT  0x6ffffef7      /* loc. of GOT for tlsdesc resolver */
+#define        DT_GNU_CONFLICT 0x6ffffef8      /* address of conflict section */
+#define        DT_GNU_LIBLIST  0x6ffffef9      /* address of library list */
+#define        DT_CONFIG       0x6ffffefa      /* configuration information */
+#define        DT_DEPAUDIT     0x6ffffefb      /* dependency auditing */
+#define        DT_AUDIT        0x6ffffefc      /* object auditing */
+#define        DT_PLTPAD       0x6ffffefd      /* pltpadding (sparcv9) */
+#define        DT_MOVETAB      0x6ffffefe      /* move table */
+#define        DT_SYMINFO      0x6ffffeff      /* syminfo table */
+#define        DT_ADDRRNGHI    0x6ffffeff
+
+#define        DT_VERSYM       0x6ffffff0      /* Address of versym section. */
+#define        DT_RELACOUNT    0x6ffffff9      /* number of RELATIVE relocations */
+#define        DT_RELCOUNT     0x6ffffffa      /* number of RELATIVE relocations */
+#define        DT_FLAGS_1      0x6ffffffb      /* state flags - see DF_1_* defs */
+#define        DT_VERDEF       0x6ffffffc      /* Address of verdef section. */
+#define        DT_VERDEFNUM    0x6ffffffd      /* Number of elems in verdef section */
+#define        DT_VERNEED      0x6ffffffe      /* Address of verneed section. */
+#define        DT_VERNEEDNUM   0x6fffffff      /* Number of elems in verneed section */
+
+#define        DT_LOPROC       0x70000000      /* First processor-specific type. */
+
+#define        DT_ARM_SYMTABSZ                 0x70000001
+#define        DT_ARM_PREEMPTMAP               0x70000002
+
+#define        DT_SPARC_REGISTER               0x70000001
+#define        DT_DEPRECATED_SPARC_REGISTER    0x7000001
+
+#define        DT_MIPS_RLD_VERSION             0x70000001
+#define        DT_MIPS_TIME_STAMP              0x70000002
+#define        DT_MIPS_ICHECKSUM               0x70000003
+#define        DT_MIPS_IVERSION                0x70000004
+#define        DT_MIPS_FLAGS                   0x70000005
+#define        DT_MIPS_BASE_ADDRESS            0x70000006
+#define        DT_MIPS_CONFLICT                0x70000008
+#define        DT_MIPS_LIBLIST                 0x70000009
+#define        DT_MIPS_LOCAL_GOTNO             0x7000000a
+#define        DT_MIPS_CONFLICTNO              0x7000000b
+#define        DT_MIPS_LIBLISTNO               0x70000010
+#define        DT_MIPS_SYMTABNO                0x70000011
+#define        DT_MIPS_UNREFEXTNO              0x70000012
+#define        DT_MIPS_GOTSYM                  0x70000013
+#define        DT_MIPS_HIPAGENO                0x70000014
+#define        DT_MIPS_RLD_MAP                 0x70000016
+#define        DT_MIPS_DELTA_CLASS             0x70000017
+#define        DT_MIPS_DELTA_CLASS_NO          0x70000018
+#define        DT_MIPS_DELTA_INSTANCE          0x70000019
+#define        DT_MIPS_DELTA_INSTANCE_NO       0x7000001A
+#define        DT_MIPS_DELTA_RELOC             0x7000001B
+#define        DT_MIPS_DELTA_RELOC_NO          0x7000001C
+#define        DT_MIPS_DELTA_SYM               0x7000001D
+#define        DT_MIPS_DELTA_SYM_NO            0x7000001E
+#define        DT_MIPS_DELTA_CLASSSYM          0x70000020
+#define        DT_MIPS_DELTA_CLASSSYM_NO       0x70000021
+#define        DT_MIPS_CXX_FLAGS               0x70000022
+#define        DT_MIPS_PIXIE_INIT              0x70000023
+#define        DT_MIPS_SYMBOL_LIB              0x70000024
+#define        DT_MIPS_LOCALPAGE_GOTIDX        0x70000025
+#define        DT_MIPS_LOCAL_GOTIDX            0x70000026
+#define        DT_MIPS_HIDDEN_GOTIDX           0x70000027
+#define        DT_MIPS_PROTECTED_GOTIDX        0x70000028
+#define        DT_MIPS_OPTIONS                 0x70000029
+#define        DT_MIPS_INTERFACE               0x7000002A
+#define        DT_MIPS_DYNSTR_ALIGN            0x7000002B
+#define        DT_MIPS_INTERFACE_SIZE          0x7000002C
+#define        DT_MIPS_RLD_TEXT_RESOLVE_ADDR   0x7000002D
+#define        DT_MIPS_PERF_SUFFIX             0x7000002E
+#define        DT_MIPS_COMPACT_SIZE            0x7000002F
+#define        DT_MIPS_GP_VALUE                0x70000030
+#define        DT_MIPS_AUX_DYNAMIC             0x70000031
+#define        DT_MIPS_PLTGOT                  0x70000032
+#define        DT_MIPS_RLD_OBJ_UPDATE          0x70000033
+#define        DT_MIPS_RWPLT                   0x70000034
+#define        DT_MIPS_RLD_MAP_REL             0x70000035
+
+#define        DT_PPC_GOT                      0x70000000
+#define        DT_PPC_TLSOPT                   0x70000001
+
+#define        DT_PPC64_GLINK                  0x70000000
+#define        DT_PPC64_OPD                    0x70000001
+#define        DT_PPC64_OPDSZ                  0x70000002
+#define        DT_PPC64_TLSOPT                 0x70000003
+
+#define        DT_AUXILIARY    0x7ffffffd      /* shared library auxiliary name */
+#define        DT_USED         0x7ffffffe      /* ignored - same as needed */
+#define        DT_FILTER       0x7fffffff      /* shared library filter name */
+#define        DT_HIPROC       0x7fffffff      /* Last processor-specific type. */
+
+/* Values for DT_FLAGS */
+#define        DF_ORIGIN       0x0001  /* Indicates that the object being loaded may
+                                  make reference to the $ORIGIN substitution
+                                  string */
+#define        DF_SYMBOLIC     0x0002  /* Indicates "symbolic" linking. */
+#define        DF_TEXTREL      0x0004  /* Indicates there may be relocations in
+                                  non-writable segments. */
+#define        DF_BIND_NOW     0x0008  /* Indicates that the dynamic linker should
+                                  process all relocations for the object
+                                  containing this entry before transferring
+                                  control to the program. */
+#define        DF_STATIC_TLS   0x0010  /* Indicates that the shared object or
+                                  executable contains code using a static
+                                  thread-local storage scheme. */
+
+/* Values for DT_FLAGS_1 */
+#define        DF_1_BIND_NOW   0x00000001      /* Same as DF_BIND_NOW */
+#define        DF_1_GLOBAL     0x00000002      /* Set the RTLD_GLOBAL for object */
+#define        DF_1_NODELETE   0x00000008      /* Set the RTLD_NODELETE for object */
+#define        DF_1_LOADFLTR   0x00000010      /* Immediate loading of filtees */
+#define        DF_1_NOOPEN     0x00000040      /* Do not allow loading on dlopen() */
+#define        DF_1_ORIGIN     0x00000080      /* Process $ORIGIN */
+#define        DF_1_INTERPOSE  0x00000400      /* Interpose all objects but main */
+#define        DF_1_NODEFLIB   0x00000800      /* Do not search default paths */
+#define        DF_1_PIE        0x08000000      /* Is position-independent executable */
+
+/* Values for l_flags. */
+#define        LL_NONE                 0x0     /* no flags */
+#define        LL_EXACT_MATCH          0x1     /* require an exact match */
+#define        LL_IGNORE_INT_VER       0x2     /* ignore version incompatibilities */
+#define        LL_REQUIRE_MINOR        0x4
+#define        LL_EXPORTS              0x8
+#define        LL_DELAY_LOAD           0x10
+#define        LL_DELTA                0x20
+
+/* Note section names */
+#define        ELF_NOTE_FREEBSD        "FreeBSD"
+#define        ELF_NOTE_NETBSD         "NetBSD"
+#define        ELF_NOTE_SOLARIS        "SUNW Solaris"
+#define        ELF_NOTE_GNU            "GNU"
+
+/* Values for n_type used in executables. */
+#define        NT_FREEBSD_ABI_TAG      1
+#define        NT_FREEBSD_NOINIT_TAG   2
+#define        NT_FREEBSD_ARCH_TAG     3
+#define        NT_FREEBSD_FEATURE_CTL  4
+
+/* NT_FREEBSD_FEATURE_CTL desc[0] bits */
+#define        NT_FREEBSD_FCTL_ASLR_DISABLE    0x00000001
+#define        NT_FREEBSD_FCTL_PROTMAX_DISABLE 0x00000002
+#define        NT_FREEBSD_FCTL_STKGAP_DISABLE  0x00000004
+#define        NT_FREEBSD_FCTL_WXNEEDED        0x00000008
+#define        NT_FREEBSD_FCTL_LA48            0x00000010
+#define        NT_FREEBSD_FCTL_ASG_DISABLE     0x00000020 /* ASLR STACK GAP Disable */
+
+/* Values for n_type.  Used in core files. */
+#define        NT_PRSTATUS     1       /* Process status. */
+#define        NT_FPREGSET     2       /* Floating point registers. */
+#define        NT_PRPSINFO     3       /* Process state info. */
+#define        NT_THRMISC      7       /* Thread miscellaneous info. */
+#define        NT_PROCSTAT_PROC        8       /* Procstat proc data. */
+#define        NT_PROCSTAT_FILES       9       /* Procstat files data. */
+#define        NT_PROCSTAT_VMMAP       10      /* Procstat vmmap data. */
+#define        NT_PROCSTAT_GROUPS      11      /* Procstat groups data. */
+#define        NT_PROCSTAT_UMASK       12      /* Procstat umask data. */
+#define        NT_PROCSTAT_RLIMIT      13      /* Procstat rlimit data. */
+#define        NT_PROCSTAT_OSREL       14      /* Procstat osreldate data. */
+#define        NT_PROCSTAT_PSSTRINGS   15      /* Procstat ps_strings data. */
+#define        NT_PROCSTAT_AUXV        16      /* Procstat auxv data. */
+#define        NT_PTLWPINFO            17      /* Thread ptrace miscellaneous info. */
+#define        NT_PPC_VMX      0x100   /* PowerPC Altivec/VMX registers */
+#define        NT_PPC_VSX      0x102   /* PowerPC VSX registers */
+#define        NT_X86_XSTATE   0x202   /* x86 XSAVE extended state. */
+#define        NT_ARM_VFP      0x400   /* ARM VFP registers */
+
+/* GNU note types. */
+#define        NT_GNU_ABI_TAG          1
+#define        NT_GNU_HWCAP            2
+#define        NT_GNU_BUILD_ID         3
+#define        NT_GNU_GOLD_VERSION     4
+#define        NT_GNU_PROPERTY_TYPE_0  5
+
+#define        GNU_PROPERTY_LOPROC                     0xc0000000
+#define        GNU_PROPERTY_HIPROC                     0xdfffffff
+
+#define        GNU_PROPERTY_X86_FEATURE_1_AND          0xc0000002
+
+#define        GNU_PROPERTY_X86_FEATURE_1_IBT          0x00000001
+#define        GNU_PROPERTY_X86_FEATURE_1_SHSTK        0x00000002
+
+/* Symbol Binding - ELFNN_ST_BIND - st_info */
+#define        STB_LOCAL       0       /* Local symbol */
+#define        STB_GLOBAL      1       /* Global symbol */
+#define        STB_WEAK        2       /* like global - lower precedence */
+#define        STB_LOOS        10      /* Start of operating system reserved range. */
+#define        STB_GNU_UNIQUE  10      /* Unique symbol (GNU) */
+#define        STB_HIOS        12      /* End of operating system reserved range. */
+#define        STB_LOPROC      13      /* reserved range for processor */
+#define        STB_HIPROC      15      /*   specific semantics. */
+
+/* Symbol type - ELFNN_ST_TYPE - st_info */
+#define        STT_NOTYPE      0       /* Unspecified type. */
+#define        STT_OBJECT      1       /* Data object. */
+#define        STT_FUNC        2       /* Function. */
+#define        STT_SECTION     3       /* Section. */
+#define        STT_FILE        4       /* Source file. */
+#define        STT_COMMON      5       /* Uninitialized common block. */
+#define        STT_TLS         6       /* TLS object. */
+#define        STT_NUM         7
+#define        STT_LOOS        10      /* Reserved range for operating system */
+#define        STT_GNU_IFUNC   10
+#define        STT_HIOS        12      /*   specific semantics. */
+#define        STT_LOPROC      13      /* Start of processor reserved range. */
+#define        STT_SPARC_REGISTER 13   /* SPARC register information. */
+#define        STT_HIPROC      15      /* End of processor reserved range. */
+
+/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */
+#define        STV_DEFAULT     0x0     /* Default visibility (see binding). */
+#define        STV_INTERNAL    0x1     /* Special meaning in relocatable objects. */
+#define        STV_HIDDEN      0x2     /* Not visible. */
+#define        STV_PROTECTED   0x3     /* Visible but not preemptible. */
+#define        STV_EXPORTED    0x4
+#define        STV_SINGLETON   0x5
+#define        STV_ELIMINATE   0x6
+
+/* Special symbol table indexes. */
+#define        STN_UNDEF       0       /* Undefined symbol index. */
+
+/* Symbol versioning flags. */
+#define        VER_DEF_CURRENT 1
+#define        VER_DEF_IDX(x)  VER_NDX(x)
+
+#define        VER_FLG_BASE    0x01
+#define        VER_FLG_WEAK    0x02
+
+#define        VER_NEED_CURRENT        1
+#define        VER_NEED_WEAK   (1u << 15)
+#define        VER_NEED_HIDDEN VER_NDX_HIDDEN
+#define        VER_NEED_IDX(x) VER_NDX(x)
+
+#define        VER_NDX_LOCAL   0
+#define        VER_NDX_GLOBAL  1
+#define        VER_NDX_GIVEN   2
+
+#define        VER_NDX_HIDDEN  (1u << 15)
+#define        VER_NDX(x)      ((x) & ~(1u << 15))
+
+#define        CA_SUNW_NULL    0
+#define        CA_SUNW_HW_1    1               /* first hardware capabilities entry */
+#define        CA_SUNW_SF_1    2               /* first software capabilities entry */
+
+/*
+ * Syminfo flag values
+ */
+#define        SYMINFO_FLG_DIRECT      0x0001  /* symbol ref has direct association */
+                                       /*      to object containing defn. */
+#define        SYMINFO_FLG_PASSTHRU    0x0002  /* ignored - see SYMINFO_FLG_FILTER */
+#define        SYMINFO_FLG_COPY        0x0004  /* symbol is a copy-reloc */
+#define        SYMINFO_FLG_LAZYLOAD    0x0008  /* object containing defn should be */
+                                       /*      lazily-loaded */
+#define        SYMINFO_FLG_DIRECTBIND  0x0010  /* ref should be bound directly to */
+                                       /*      object containing defn. */
+#define        SYMINFO_FLG_NOEXTDIRECT 0x0020  /* don't let an external reference */
+                                       /*      directly bind to this symbol */
+#define        SYMINFO_FLG_FILTER      0x0002  /* symbol ref is associated to a */
+#define        SYMINFO_FLG_AUXILIARY   0x0040  /*      standard or auxiliary filter */
+
+/*
+ * Syminfo.si_boundto values.
+ */
+#define        SYMINFO_BT_SELF         0xffff  /* symbol bound to self */
+#define        SYMINFO_BT_PARENT       0xfffe  /* symbol bound to parent */
+#define        SYMINFO_BT_NONE         0xfffd  /* no special symbol binding */
+#define        SYMINFO_BT_EXTERN       0xfffc  /* symbol defined as external */
+#define        SYMINFO_BT_LOWRESERVE   0xff00  /* beginning of reserved entries */
+
+/*
+ * Syminfo version values.
+ */
+#define        SYMINFO_NONE            0       /* Syminfo version */
+#define        SYMINFO_CURRENT         1
+#define        SYMINFO_NUM             2
+
+/* Values for ch_type (compressed section headers). */
+#define        ELFCOMPRESS_ZLIB        1       /* ZLIB/DEFLATE */
+#define        ELFCOMPRESS_LOOS        0x60000000      /* OS-specific */
+#define        ELFCOMPRESS_HIOS        0x6fffffff
+#define        ELFCOMPRESS_LOPROC      0x70000000      /* Processor-specific */
+#define        ELFCOMPRESS_HIPROC      0x7fffffff
+
+/* Values for a_type. */
+#define        AT_NULL         0       /* Terminates the vector. */
+#define        AT_IGNORE       1       /* Ignored entry. */
+#define        AT_EXECFD       2       /* File descriptor of program to load. */
+#define        AT_PHDR         3       /* Program header of program already loaded. */
+#define        AT_PHENT        4       /* Size of each program header entry. */
+#define        AT_PHNUM        5       /* Number of program header entries. */
+#define        AT_PAGESZ       6       /* Page size in bytes. */
+#define        AT_BASE         7       /* Interpreter's base address. */
+#define        AT_FLAGS        8       /* Flags. */
+#define        AT_ENTRY        9       /* Where interpreter should transfer control. */
+#define        AT_NOTELF       10      /* Program is not ELF ?? */
+#define        AT_UID          11      /* Real uid. */
+#define        AT_EUID         12      /* Effective uid. */
+#define        AT_GID          13      /* Real gid. */
+#define        AT_EGID         14      /* Effective gid. */
+#define        AT_EXECPATH     15      /* Path to the executable. */
+#define        AT_CANARY       16      /* Canary for SSP. */
+#define        AT_CANARYLEN    17      /* Length of the canary. */
+#define        AT_OSRELDATE    18      /* OSRELDATE. */
+#define        AT_NCPUS        19      /* Number of CPUs. */
+#define        AT_PAGESIZES    20      /* Pagesizes. */
+#define        AT_PAGESIZESLEN 21      /* Number of pagesizes. */
+#define        AT_TIMEKEEP     22      /* Pointer to timehands. */
+#define        AT_STACKPROT    23      /* Initial stack protection. */
+#define        AT_EHDRFLAGS    24      /* e_flags field from elf hdr */
+#define        AT_HWCAP        25      /* CPU feature flags. */
+#define        AT_HWCAP2       26      /* CPU feature flags 2. */
+#define        AT_BSDFLAGS     27      /* ELF BSD Flags. */
+#define        AT_ARGC         28      /* Argument count */
+#define        AT_ARGV         29      /* Argument vector */
+#define        AT_ENVC         30      /* Environment count */
+#define        AT_ENVV         31      /* Environment vector */
+#define        AT_PS_STRINGS   32      /* struct ps_strings */
+#define        AT_FXRNG        33      /* Pointer to root RNG seed version. */
+
+#define        AT_COUNT        34      /* Count of defined aux entry types. */
+
+/*
+ * Relocation types.
+ *
+ * All machine architectures are defined here to allow tools on one to
+ * handle others.
+ */
+
+#define        R_386_NONE              0       /* No relocation. */
+#define        R_386_32                1       /* Add symbol value. */
+#define        R_386_PC32              2       /* Add PC-relative symbol value. */
+#define        R_386_GOT32             3       /* Add PC-relative GOT offset. */
+#define        R_386_PLT32             4       /* Add PC-relative PLT offset. */
+#define        R_386_COPY              5       /* Copy data from shared object. */
+#define        R_386_GLOB_DAT          6       /* Set GOT entry to data address. */
+#define        R_386_JMP_SLOT          7       /* Set GOT entry to code address. */
+#define        R_386_RELATIVE          8       /* Add load address of shared object. */
+#define        R_386_GOTOFF            9       /* Add GOT-relative symbol address. */
+#define        R_386_GOTPC             10      /* Add PC-relative GOT table address. */
+#define        R_386_32PLT             11
+#define        R_386_TLS_TPOFF         14      /* Negative offset in static TLS block */
+#define        R_386_TLS_IE            15      /* Absolute address of GOT for -ve static TLS */
+#define        R_386_TLS_GOTIE         16      /* GOT entry for negative static TLS block */
+#define        R_386_TLS_LE            17      /* Negative offset relative to static TLS */
+#define        R_386_TLS_GD            18      /* 32 bit offset to GOT (index,off) pair */
+#define        R_386_TLS_LDM           19      /* 32 bit offset to GOT (index,zero) pair */
+#define        R_386_16                20
+#define        R_386_PC16              21
+#define        R_386_8                 22
+#define        R_386_PC8               23
+#define        R_386_TLS_GD_32         24      /* 32 bit offset to GOT (index,off) pair */
+#define        R_386_TLS_GD_PUSH       25      /* pushl instruction for Sun ABI GD sequence */
+#define        R_386_TLS_GD_CALL       26      /* call instruction for Sun ABI GD sequence */
+#define        R_386_TLS_GD_POP        27      /* popl instruction for Sun ABI GD sequence */
+#define        R_386_TLS_LDM_32        28      /* 32 bit offset to GOT (index,zero) pair */
+#define        R_386_TLS_LDM_PUSH      29      /* pushl instruction for Sun ABI LD sequence */
+#define        R_386_TLS_LDM_CALL      30      /* call instruction for Sun ABI LD sequence */
+#define        R_386_TLS_LDM_POP       31      /* popl instruction for Sun ABI LD sequence */
+#define        R_386_TLS_LDO_32        32      /* 32 bit offset from start of TLS block */
+#define        R_386_TLS_IE_32         33      /* 32 bit offset to GOT static TLS offset entry */
+#define        R_386_TLS_LE_32         34      /* 32 bit offset within static TLS block */
+#define        R_386_TLS_DTPMOD32      35      /* GOT entry containing TLS index */
+#define        R_386_TLS_DTPOFF32      36      /* GOT entry containing TLS offset */
+#define        R_386_TLS_TPOFF32       37      /* GOT entry of -ve static TLS offset */
+#define        R_386_SIZE32            38
+#define        R_386_TLS_GOTDESC       39
+#define        R_386_TLS_DESC_CALL     40
+#define        R_386_TLS_DESC          41
+#define        R_386_IRELATIVE         42      /* PLT entry resolved indirectly at runtime */
+#define        R_386_GOT32X            43
+
+#define        R_AARCH64_NONE          0       /* No relocation */
+#define        R_AARCH64_ABS64         257     /* Absolute offset */
+#define        R_AARCH64_ABS32         258     /* Absolute, 32-bit overflow check */
+#define        R_AARCH64_ABS16         259     /* Absolute, 16-bit overflow check */
+#define        R_AARCH64_PREL64        260     /* PC relative */
+#define        R_AARCH64_PREL32        261     /* PC relative, 32-bit overflow check */
+#define        R_AARCH64_PREL16        262     /* PC relative, 16-bit overflow check */
+#define        R_AARCH64_TSTBR14       279     /* TBZ/TBNZ immediate */
+#define        R_AARCH64_CONDBR19      280     /* Conditional branch immediate */
+#define        R_AARCH64_JUMP26        282     /* Branch immediate */
+#define        R_AARCH64_CALL26        283     /* Call immediate */
+#define        R_AARCH64_COPY          1024    /* Copy data from shared object */
+#define        R_AARCH64_GLOB_DAT      1025    /* Set GOT entry to data address */
+#define        R_AARCH64_JUMP_SLOT     1026    /* Set GOT entry to code address */
+#define        R_AARCH64_RELATIVE      1027    /* Add load address of shared object */
+#define        R_AARCH64_TLS_DTPREL64  1028
+#define        R_AARCH64_TLS_DTPMOD64  1029
+#define        R_AARCH64_TLS_TPREL64   1030
+#define        R_AARCH64_TLSDESC       1031    /* Identify the TLS descriptor */
+#define        R_AARCH64_IRELATIVE     1032
+
+#define        R_ARM_NONE              0       /* No relocation. */
+#define        R_ARM_PC24              1
+#define        R_ARM_ABS32             2
+#define        R_ARM_REL32             3
+#define        R_ARM_PC13              4
+#define        R_ARM_ABS16             5
+#define        R_ARM_ABS12             6
+#define        R_ARM_THM_ABS5          7
+#define        R_ARM_ABS8              8
+#define        R_ARM_SBREL32           9
+#define        R_ARM_THM_PC22          10
+#define        R_ARM_THM_PC8           11
+#define        R_ARM_AMP_VCALL9        12
+#define        R_ARM_SWI24             13
+#define        R_ARM_THM_SWI8          14
+#define        R_ARM_XPC25             15
+#define        R_ARM_THM_XPC22         16
+/* TLS relocations */
+#define        R_ARM_TLS_DTPMOD32      17      /* ID of module containing symbol */
+#define        R_ARM_TLS_DTPOFF32      18      /* Offset in TLS block */
+#define        R_ARM_TLS_TPOFF32       19      /* Offset in static TLS block */
+#define        R_ARM_COPY              20      /* Copy data from shared object. */
+#define        R_ARM_GLOB_DAT          21      /* Set GOT entry to data address. */
+#define        R_ARM_JUMP_SLOT         22      /* Set GOT entry to code address. */
+#define        R_ARM_RELATIVE          23      /* Add load address of shared object. */
+#define        R_ARM_GOTOFF            24      /* Add GOT-relative symbol address. */
+#define        R_ARM_GOTPC             25      /* Add PC-relative GOT table address. */
+#define        R_ARM_GOT32             26      /* Add PC-relative GOT offset. */
+#define        R_ARM_PLT32             27      /* Add PC-relative PLT offset. */
+#define        R_ARM_GNU_VTENTRY       100
+#define        R_ARM_GNU_VTINHERIT     101
+#define        R_ARM_RSBREL32          250
+#define        R_ARM_THM_RPC22         251
+#define        R_ARM_RREL32            252
+#define        R_ARM_RABS32            253
+#define        R_ARM_RPC24             254
+#define        R_ARM_RBASE             255
+
+/*     Name                    Value      Field        Calculation */
+#define        R_IA_64_NONE            0       /* None */
+#define        R_IA_64_IMM14           0x21    /* immediate14  S + A */
+#define        R_IA_64_IMM22           0x22    /* immediate22  S + A */
+#define        R_IA_64_IMM64           0x23    /* immediate64  S + A */
+#define        R_IA_64_DIR32MSB        0x24    /* word32 MSB   S + A */
+#define        R_IA_64_DIR32LSB        0x25    /* word32 LSB   S + A */
+#define        R_IA_64_DIR64MSB        0x26    /* word64 MSB   S + A */
+#define        R_IA_64_DIR64LSB        0x27    /* word64 LSB   S + A */
+#define        R_IA_64_GPREL22         0x2a    /* immediate22  @gprel(S + A) */
+#define        R_IA_64_GPREL64I        0x2b    /* immediate64  @gprel(S + A) */
+#define        R_IA_64_GPREL32MSB      0x2c    /* word32 MSB   @gprel(S + A) */
+#define        R_IA_64_GPREL32LSB      0x2d    /* word32 LSB   @gprel(S + A) */
+#define        R_IA_64_GPREL64MSB      0x2e    /* word64 MSB   @gprel(S + A) */
+#define        R_IA_64_GPREL64LSB      0x2f    /* word64 LSB   @gprel(S + A) */
+#define        R_IA_64_LTOFF22         0x32    /* immediate22  @ltoff(S + A) */
+#define        R_IA_64_LTOFF64I        0x33    /* immediate64  @ltoff(S + A) */
+#define        R_IA_64_PLTOFF22        0x3a    /* immediate22  @pltoff(S + A) */
+#define        R_IA_64_PLTOFF64I       0x3b    /* immediate64  @pltoff(S + A) */
+#define        R_IA_64_PLTOFF64MSB     0x3e    /* word64 MSB   @pltoff(S + A) */
+#define        R_IA_64_PLTOFF64LSB     0x3f    /* word64 LSB   @pltoff(S + A) */
+#define        R_IA_64_FPTR64I         0x43    /* immediate64  @fptr(S + A) */
+#define        R_IA_64_FPTR32MSB       0x44    /* word32 MSB   @fptr(S + A) */
+#define        R_IA_64_FPTR32LSB       0x45    /* word32 LSB   @fptr(S + A) */
+#define        R_IA_64_FPTR64MSB       0x46    /* word64 MSB   @fptr(S + A) */
+#define        R_IA_64_FPTR64LSB       0x47    /* word64 LSB   @fptr(S + A) */
+#define        R_IA_64_PCREL60B        0x48    /* immediate60 form1 S + A - P */
+#define        R_IA_64_PCREL21B        0x49    /* immediate21 form1 S + A - P */
+#define        R_IA_64_PCREL21M        0x4a    /* immediate21 form2 S + A - P */
+#define        R_IA_64_PCREL21F        0x4b    /* immediate21 form3 S + A - P */
+#define        R_IA_64_PCREL32MSB      0x4c    /* word32 MSB   S + A - P */
+#define        R_IA_64_PCREL32LSB      0x4d    /* word32 LSB   S + A - P */
+#define        R_IA_64_PCREL64MSB      0x4e    /* word64 MSB   S + A - P */
+#define        R_IA_64_PCREL64LSB      0x4f    /* word64 LSB   S + A - P */
+#define        R_IA_64_LTOFF_FPTR22    0x52    /* immediate22  @ltoff(@fptr(S + A)) */
+#define        R_IA_64_LTOFF_FPTR64I   0x53    /* immediate64  @ltoff(@fptr(S + A)) */
+#define        R_IA_64_LTOFF_FPTR32MSB 0x54    /* word32 MSB   @ltoff(@fptr(S + A)) */
+#define        R_IA_64_LTOFF_FPTR32LSB 0x55    /* word32 LSB   @ltoff(@fptr(S + A)) */
+#define        R_IA_64_LTOFF_FPTR64MSB 0x56    /* word64 MSB   @ltoff(@fptr(S + A)) */
+#define        R_IA_64_LTOFF_FPTR64LSB 0x57    /* word64 LSB   @ltoff(@fptr(S + A)) */
+#define        R_IA_64_SEGREL32MSB     0x5c    /* word32 MSB   @segrel(S + A) */
+#define        R_IA_64_SEGREL32LSB     0x5d    /* word32 LSB   @segrel(S + A) */
+#define        R_IA_64_SEGREL64MSB     0x5e    /* word64 MSB   @segrel(S + A) */
+#define        R_IA_64_SEGREL64LSB     0x5f    /* word64 LSB   @segrel(S + A) */
+#define        R_IA_64_SECREL32MSB     0x64    /* word32 MSB   @secrel(S + A) */
+#define        R_IA_64_SECREL32LSB     0x65    /* word32 LSB   @secrel(S + A) */
+#define        R_IA_64_SECREL64MSB     0x66    /* word64 MSB   @secrel(S + A) */
+#define        R_IA_64_SECREL64LSB     0x67    /* word64 LSB   @secrel(S + A) */
+#define        R_IA_64_REL32MSB        0x6c    /* word32 MSB   BD + A */
+#define        R_IA_64_REL32LSB        0x6d    /* word32 LSB   BD + A */
+#define        R_IA_64_REL64MSB        0x6e    /* word64 MSB   BD + A */
+#define        R_IA_64_REL64LSB        0x6f    /* word64 LSB   BD + A */
+#define        R_IA_64_LTV32MSB        0x74    /* word32 MSB   S + A */
+#define        R_IA_64_LTV32LSB        0x75    /* word32 LSB   S + A */
+#define        R_IA_64_LTV64MSB        0x76    /* word64 MSB   S + A */
+#define        R_IA_64_LTV64LSB        0x77    /* word64 LSB   S + A */
+#define        R_IA_64_PCREL21BI       0x79    /* immediate21 form1 S + A - P */
+#define        R_IA_64_PCREL22         0x7a    /* immediate22  S + A - P */
+#define        R_IA_64_PCREL64I        0x7b    /* immediate64  S + A - P */
+#define        R_IA_64_IPLTMSB         0x80    /* function descriptor MSB special */
+#define        R_IA_64_IPLTLSB         0x81    /* function descriptor LSB speciaal */
+#define        R_IA_64_SUB             0x85    /* immediate64  A - S */
+#define        R_IA_64_LTOFF22X        0x86    /* immediate22  special */
+#define        R_IA_64_LDXMOV          0x87    /* immediate22  special */
+#define        R_IA_64_TPREL14         0x91    /* imm14        @tprel(S + A) */
+#define        R_IA_64_TPREL22         0x92    /* imm22        @tprel(S + A) */
+#define        R_IA_64_TPREL64I        0x93    /* imm64        @tprel(S + A) */
+#define        R_IA_64_TPREL64MSB      0x96    /* word64 MSB   @tprel(S + A) */
+#define        R_IA_64_TPREL64LSB      0x97    /* word64 LSB   @tprel(S + A) */
+#define        R_IA_64_LTOFF_TPREL22   0x9a    /* imm22        @ltoff(@tprel(S+A)) */
+#define        R_IA_64_DTPMOD64MSB     0xa6    /* word64 MSB   @dtpmod(S + A) */
+#define        R_IA_64_DTPMOD64LSB     0xa7    /* word64 LSB   @dtpmod(S + A) */
+#define        R_IA_64_LTOFF_DTPMOD22  0xaa    /* imm22        @ltoff(@dtpmod(S+A)) */
+#define        R_IA_64_DTPREL14        0xb1    /* imm14        @dtprel(S + A) */
+#define        R_IA_64_DTPREL22        0xb2    /* imm22        @dtprel(S + A) */
+#define        R_IA_64_DTPREL64I       0xb3    /* imm64        @dtprel(S + A) */
+#define        R_IA_64_DTPREL32MSB     0xb4    /* word32 MSB   @dtprel(S + A) */
+#define        R_IA_64_DTPREL32LSB     0xb5    /* word32 LSB   @dtprel(S + A) */
+#define        R_IA_64_DTPREL64MSB     0xb6    /* word64 MSB   @dtprel(S + A) */
+#define        R_IA_64_DTPREL64LSB     0xb7    /* word64 LSB   @dtprel(S + A) */
+#define        R_IA_64_LTOFF_DTPREL22  0xba    /* imm22        @ltoff(@dtprel(S+A)) */
+
+#define        R_MIPS_NONE     0       /* No reloc */
+#define        R_MIPS_16       1       /* Direct 16 bit */
+#define        R_MIPS_32       2       /* Direct 32 bit */
+#define        R_MIPS_REL32    3       /* PC relative 32 bit */
+#define        R_MIPS_26       4       /* Direct 26 bit shifted */
+#define        R_MIPS_HI16     5       /* High 16 bit */
+#define        R_MIPS_LO16     6       /* Low 16 bit */
+#define        R_MIPS_GPREL16  7       /* GP relative 16 bit */
+#define        R_MIPS_LITERAL  8       /* 16 bit literal entry */
+#define        R_MIPS_GOT16    9       /* 16 bit GOT entry */
+#define        R_MIPS_PC16     10      /* PC relative 16 bit */
+#define        R_MIPS_CALL16   11      /* 16 bit GOT entry for function */
+#define        R_MIPS_GPREL32  12      /* GP relative 32 bit */
+#define        R_MIPS_64       18      /* Direct 64 bit */
+#define        R_MIPS_GOT_DISP 19
+#define        R_MIPS_GOT_PAGE 20
+#define        R_MIPS_GOT_OFST 21
+#define        R_MIPS_GOT_HI16 22      /* GOT HI 16 bit */
+#define        R_MIPS_GOT_LO16 23      /* GOT LO 16 bit */
+#define        R_MIPS_SUB      24
+#define        R_MIPS_CALLHI16 30      /* upper 16 bit GOT entry for function */
+#define        R_MIPS_CALLLO16 31      /* lower 16 bit GOT entry for function */
+#define        R_MIPS_JALR     37
+#define        R_MIPS_TLS_GD   42
+#define        R_MIPS_COPY     126
+#define        R_MIPS_JUMP_SLOT        127
+
+#define        R_PPC_NONE              0       /* No relocation. */
+#define        R_PPC_ADDR32            1
+#define        R_PPC_ADDR24            2
+#define        R_PPC_ADDR16            3
+#define        R_PPC_ADDR16_LO         4
+#define        R_PPC_ADDR16_HI         5
+#define        R_PPC_ADDR16_HA         6
+#define        R_PPC_ADDR14            7
+#define        R_PPC_ADDR14_BRTAKEN    8
+#define        R_PPC_ADDR14_BRNTAKEN   9
+#define        R_PPC_REL24             10
+#define        R_PPC_REL14             11
+#define        R_PPC_REL14_BRTAKEN     12
+#define        R_PPC_REL14_BRNTAKEN    13
+#define        R_PPC_GOT16             14
+#define        R_PPC_GOT16_LO          15
+#define        R_PPC_GOT16_HI          16
+#define        R_PPC_GOT16_HA          17
+#define        R_PPC_PLTREL24          18
+#define        R_PPC_COPY              19
+#define        R_PPC_GLOB_DAT          20
+#define        R_PPC_JMP_SLOT          21
+#define        R_PPC_RELATIVE          22
+#define        R_PPC_LOCAL24PC         23
+#define        R_PPC_UADDR32           24
+#define        R_PPC_UADDR16           25
+#define        R_PPC_REL32             26
+#define        R_PPC_PLT32             27
+#define        R_PPC_PLTREL32          28
+#define        R_PPC_PLT16_LO          29
+#define        R_PPC_PLT16_HI          30
+#define        R_PPC_PLT16_HA          31
+#define        R_PPC_SDAREL16          32
+#define        R_PPC_SECTOFF           33
+#define        R_PPC_SECTOFF_LO        34
+#define        R_PPC_SECTOFF_HI        35
+#define        R_PPC_SECTOFF_HA        36
+#define        R_PPC_IRELATIVE         248
+
+/*
+ * 64-bit relocations
+ */
+#define        R_PPC64_ADDR64          38
+#define        R_PPC64_ADDR16_HIGHER   39
+#define        R_PPC64_ADDR16_HIGHERA  40
+#define        R_PPC64_ADDR16_HIGHEST  41
+#define        R_PPC64_ADDR16_HIGHESTA 42
+#define        R_PPC64_UADDR64         43
+#define        R_PPC64_REL64           44
+#define        R_PPC64_PLT64           45
+#define        R_PPC64_PLTREL64        46
+#define        R_PPC64_TOC16           47
+#define        R_PPC64_TOC16_LO        48
+#define        R_PPC64_TOC16_HI        49
+#define        R_PPC64_TOC16_HA        50
+#define        R_PPC64_TOC             51
+#define        R_PPC64_DTPMOD64        68
+#define        R_PPC64_TPREL64         73
+#define        R_PPC64_DTPREL64        78
+
+/*
+ * TLS relocations
+ */
+#define        R_PPC_TLS               67
+#define        R_PPC_DTPMOD32          68
+#define        R_PPC_TPREL16           69
+#define        R_PPC_TPREL16_LO        70
+#define        R_PPC_TPREL16_HI        71
+#define        R_PPC_TPREL16_HA        72
+#define        R_PPC_TPREL32           73
+#define        R_PPC_DTPREL16          74
+#define        R_PPC_DTPREL16_LO       75
+#define        R_PPC_DTPREL16_HI       76
+#define        R_PPC_DTPREL16_HA       77
+#define        R_PPC_DTPREL32          78
+#define        R_PPC_GOT_TLSGD16       79
+#define        R_PPC_GOT_TLSGD16_LO    80
+#define        R_PPC_GOT_TLSGD16_HI    81
+#define        R_PPC_GOT_TLSGD16_HA    82
+#define        R_PPC_GOT_TLSLD16       83
+#define        R_PPC_GOT_TLSLD16_LO    84
+#define        R_PPC_GOT_TLSLD16_HI    85
+#define        R_PPC_GOT_TLSLD16_HA    86
+#define        R_PPC_GOT_TPREL16       87
+#define        R_PPC_GOT_TPREL16_LO    88
+#define        R_PPC_GOT_TPREL16_HI    89
+#define        R_PPC_GOT_TPREL16_HA    90
+
+/*
+ * The remaining relocs are from the Embedded ELF ABI, and are not in the
+ *  SVR4 ELF ABI.
+ */
+
+#define        R_PPC_EMB_NADDR32       101
+#define        R_PPC_EMB_NADDR16       102
+#define        R_PPC_EMB_NADDR16_LO    103
+#define        R_PPC_EMB_NADDR16_HI    104
+#define        R_PPC_EMB_NADDR16_HA    105
+#define        R_PPC_EMB_SDAI16        106
+#define        R_PPC_EMB_SDA2I16       107
+#define        R_PPC_EMB_SDA2REL       108
+#define        R_PPC_EMB_SDA21         109
+#define        R_PPC_EMB_MRKREF        110
+#define        R_PPC_EMB_RELSEC16      111
+#define        R_PPC_EMB_RELST_LO      112
+#define        R_PPC_EMB_RELST_HI      113
+#define        R_PPC_EMB_RELST_HA      114
+#define        R_PPC_EMB_BIT_FLD       115
+#define        R_PPC_EMB_RELSDA        116
+
+/*
+ * RISC-V relocation types.
+ */
+
+/* Relocation types used by the dynamic linker. */
+#define        R_RISCV_NONE            0
+#define        R_RISCV_32              1
+#define        R_RISCV_64              2
+#define        R_RISCV_RELATIVE        3
+#define        R_RISCV_COPY            4
+#define        R_RISCV_JUMP_SLOT       5
+#define        R_RISCV_TLS_DTPMOD32    6
+#define        R_RISCV_TLS_DTPMOD64    7
+#define        R_RISCV_TLS_DTPREL32    8
+#define        R_RISCV_TLS_DTPREL64    9
+#define        R_RISCV_TLS_TPREL32     10
+#define        R_RISCV_TLS_TPREL64     11
+
+/* Relocation types not used by the dynamic linker. */
+#define        R_RISCV_BRANCH          16
+#define        R_RISCV_JAL             17
+#define        R_RISCV_CALL            18
+#define        R_RISCV_CALL_PLT        19
+#define        R_RISCV_GOT_HI20        20
+#define        R_RISCV_TLS_GOT_HI20    21
+#define        R_RISCV_TLS_GD_HI20     22
+#define        R_RISCV_PCREL_HI20      23
+#define        R_RISCV_PCREL_LO12_I    24
+#define        R_RISCV_PCREL_LO12_S    25
+#define        R_RISCV_HI20            26
+#define        R_RISCV_LO12_I          27
+#define        R_RISCV_LO12_S          28
+#define        R_RISCV_TPREL_HI20      29
+#define        R_RISCV_TPREL_LO12_I    30
+#define        R_RISCV_TPREL_LO12_S    31
+#define        R_RISCV_TPREL_ADD       32
+#define        R_RISCV_ADD8            33
+#define        R_RISCV_ADD16           34
+#define        R_RISCV_ADD32           35
+#define        R_RISCV_ADD64           36
+#define        R_RISCV_SUB8            37
+#define        R_RISCV_SUB16           38
+#define        R_RISCV_SUB32           39
+#define        R_RISCV_SUB64           40
+#define        R_RISCV_GNU_VTINHERIT   41
+#define        R_RISCV_GNU_VTENTRY     42
+#define        R_RISCV_ALIGN           43
+#define        R_RISCV_RVC_BRANCH      44
+#define        R_RISCV_RVC_JUMP        45
+#define        R_RISCV_RVC_LUI         46
+#define        R_RISCV_GPREL_I         47
+#define        R_RISCV_GPREL_S         48
+#define        R_RISCV_TPREL_I         49
+#define        R_RISCV_TPREL_S         50
+#define        R_RISCV_RELAX           51
+#define        R_RISCV_SUB6            52
+#define        R_RISCV_SET6            53
+#define        R_RISCV_SET8            54
+#define        R_RISCV_SET16           55
+#define        R_RISCV_SET32           56
+#define        R_RISCV_32_PCREL        57
+#define        R_RISCV_IRELATIVE       58
+
+#define        R_SPARC_NONE            0
+#define        R_SPARC_8               1
+#define        R_SPARC_16              2
+#define        R_SPARC_32              3
+#define        R_SPARC_DISP8           4
+#define        R_SPARC_DISP16          5
+#define        R_SPARC_DISP32          6
+#define        R_SPARC_WDISP30         7
+#define        R_SPARC_WDISP22         8
+#define        R_SPARC_HI22            9
+#define        R_SPARC_22              10
+#define        R_SPARC_13              11
+#define        R_SPARC_LO10            12
+#define        R_SPARC_GOT10           13
+#define        R_SPARC_GOT13           14
+#define        R_SPARC_GOT22           15
+#define        R_SPARC_PC10            16
+#define        R_SPARC_PC22            17
+#define        R_SPARC_WPLT30          18
+#define        R_SPARC_COPY            19
+#define        R_SPARC_GLOB_DAT        20
+#define        R_SPARC_JMP_SLOT        21
+#define        R_SPARC_RELATIVE        22
+#define        R_SPARC_UA32            23
+#define        R_SPARC_PLT32           24
+#define        R_SPARC_HIPLT22         25
+#define        R_SPARC_LOPLT10         26
+#define        R_SPARC_PCPLT32         27
+#define        R_SPARC_PCPLT22         28
+#define        R_SPARC_PCPLT10         29
+#define        R_SPARC_10              30
+#define        R_SPARC_11              31
+#define        R_SPARC_64              32
+#define        R_SPARC_OLO10           33
+#define        R_SPARC_HH22            34
+#define        R_SPARC_HM10            35
+#define        R_SPARC_LM22            36
+#define        R_SPARC_PC_HH22         37
+#define        R_SPARC_PC_HM10         38
+#define        R_SPARC_PC_LM22         39
+#define        R_SPARC_WDISP16         40
+#define        R_SPARC_WDISP19         41
+#define        R_SPARC_GLOB_JMP        42
+#define        R_SPARC_7               43
+#define        R_SPARC_5               44
+#define        R_SPARC_6               45
+#define        R_SPARC_DISP64          46
+#define        R_SPARC_PLT64           47
+#define        R_SPARC_HIX22           48
+#define        R_SPARC_LOX10           49
+#define        R_SPARC_H44             50
+#define        R_SPARC_M44             51
+#define        R_SPARC_L44             52
+#define        R_SPARC_REGISTER        53
+#define        R_SPARC_UA64            54
+#define        R_SPARC_UA16            55
+#define        R_SPARC_TLS_GD_HI22     56
+#define        R_SPARC_TLS_GD_LO10     57
+#define        R_SPARC_TLS_GD_ADD      58
+#define        R_SPARC_TLS_GD_CALL     59
+#define        R_SPARC_TLS_LDM_HI22    60
+#define        R_SPARC_TLS_LDM_LO10    61
+#define        R_SPARC_TLS_LDM_ADD     62
+#define        R_SPARC_TLS_LDM_CALL    63
+#define        R_SPARC_TLS_LDO_HIX22   64
+#define        R_SPARC_TLS_LDO_LOX10   65
+#define        R_SPARC_TLS_LDO_ADD     66
+#define        R_SPARC_TLS_IE_HI22     67
+#define        R_SPARC_TLS_IE_LO10     68
+#define        R_SPARC_TLS_IE_LD       69
+#define        R_SPARC_TLS_IE_LDX      70
+#define        R_SPARC_TLS_IE_ADD      71
+#define        R_SPARC_TLS_LE_HIX22    72
+#define        R_SPARC_TLS_LE_LOX10    73
+#define        R_SPARC_TLS_DTPMOD32    74
+#define        R_SPARC_TLS_DTPMOD64    75
+#define        R_SPARC_TLS_DTPOFF32    76
+#define        R_SPARC_TLS_DTPOFF64    77
+#define        R_SPARC_TLS_TPOFF32     78
+#define        R_SPARC_TLS_TPOFF64     79
+
+#define        R_X86_64_NONE           0       /* No relocation. */
+#define        R_X86_64_64             1       /* Add 64 bit symbol value. */
+#define        R_X86_64_PC32           2       /* PC-relative 32 bit signed sym value. */
+#define        R_X86_64_GOT32          3       /* PC-relative 32 bit GOT offset. */
+#define        R_X86_64_PLT32          4       /* PC-relative 32 bit PLT offset. */
+#define        R_X86_64_COPY           5       /* Copy data from shared object. */
+#define        R_X86_64_GLOB_DAT       6       /* Set GOT entry to data address. */
+#define        R_X86_64_JMP_SLOT       7       /* Set GOT entry to code address. */
+#define        R_X86_64_RELATIVE       8       /* Add load address of shared object. */
+#define        R_X86_64_GOTPCREL       9       /* Add 32 bit signed pcrel offset to GOT. */
+#define        R_X86_64_32             10      /* Add 32 bit zero extended symbol value */
+#define        R_X86_64_32S            11      /* Add 32 bit sign extended symbol value */
+#define        R_X86_64_16             12      /* Add 16 bit zero extended symbol value */
+#define        R_X86_64_PC16           13      /* Add 16 bit signed extended pc relative symbol value */
+#define        R_X86_64_8              14      /* Add 8 bit zero extended symbol value */
+#define        R_X86_64_PC8            15      /* Add 8 bit signed extended pc relative symbol value */
+#define        R_X86_64_DTPMOD64       16      /* ID of module containing symbol */
+#define        R_X86_64_DTPOFF64       17      /* Offset in TLS block */
+#define        R_X86_64_TPOFF64        18      /* Offset in static TLS block */
+#define        R_X86_64_TLSGD          19      /* PC relative offset to GD GOT entry */
+#define        R_X86_64_TLSLD          20      /* PC relative offset to LD GOT entry */
+#define        R_X86_64_DTPOFF32       21      /* Offset in TLS block */
+#define        R_X86_64_GOTTPOFF       22      /* PC relative offset to IE GOT entry */
+#define        R_X86_64_TPOFF32        23      /* Offset in static TLS block */
+#define        R_X86_64_PC64           24      /* PC-relative 64 bit signed sym value. */
+#define        R_X86_64_GOTOFF64       25
+#define        R_X86_64_GOTPC32        26
+#define        R_X86_64_GOT64          27
+#define        R_X86_64_GOTPCREL64     28
+#define        R_X86_64_GOTPC64        29
+#define        R_X86_64_GOTPLT64       30
+#define        R_X86_64_PLTOFF64       31
+#define        R_X86_64_SIZE32         32
+#define        R_X86_64_SIZE64         33
+#define        R_X86_64_GOTPC32_TLSDESC 34
+#define        R_X86_64_TLSDESC_CALL   35
+#define        R_X86_64_TLSDESC        36
+#define        R_X86_64_IRELATIVE      37
+#define        R_X86_64_RELATIVE64     38
+/* 39 and 40 were BND-related, already decomissioned */
+#define        R_X86_64_GOTPCRELX      41
+#define        R_X86_64_REX_GOTPCRELX  42
+
+#define        ELF_BSDF_SIGFASTBLK     0x0001  /* Kernel supports fast sigblock */
+
+#endif /* !_SYS_ELF_COMMON_H_ */
index 9562436..a685da1 100644 (file)
@@ -3,8 +3,8 @@
 // recognized in your jurisdiction.
 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
 
-#ifndef CPPTL_JSON_ALLOCATOR_H_INCLUDED
-#define CPPTL_JSON_ALLOCATOR_H_INCLUDED
+#ifndef JSON_ALLOCATOR_H_INCLUDED
+#define JSON_ALLOCATOR_H_INCLUDED
 
 #include <cstring>
 #include <memory>
 #endif
 
 namespace Json {
-template<typename T>
-class SecureAllocator {
-       public:
-               // Type definitions
-               using value_type      = T;
-               using pointer         = T*;
-               using const_pointer   = const T*;
-               using reference       = T&;
-               using const_reference = const T&;
-               using size_type       = std::size_t;
-               using difference_type = std::ptrdiff_t;
-
-               /**
-                * Allocate memory for N items using the standard allocator.
-                */
-               pointer allocate(size_type n) {
-                       // allocate using "global operator new"
-                       return static_cast<pointer>(::operator new(n * sizeof(T)));
-               }
-
-               /**
-                * Release memory which was allocated for N items at pointer P.
-                *
-                * The memory block is filled with zeroes before being released.
-                * The pointer argument is tagged as "volatile" to prevent the
-                * compiler optimizing out this critical step.
-                */
-               void deallocate(volatile pointer p, size_type n) {
-                       std::memset(p, 0, n * sizeof(T));
-                       // free using "global operator delete"
-                       ::operator delete(p);
-               }
-
-               /**
-                * Construct an item in-place at pointer P.
-                */
-               template<typename... Args>
-               void construct(pointer p, Args&&... args) {
-                       // construct using "placement new" and "perfect forwarding"
-                       ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
-               }
-
-               size_type max_size() const {
-                       return size_t(-1) / sizeof(T);
-               }
-
-               pointer address( reference x ) const {
-                       return std::addressof(x);
-               }
-
-               const_pointer address( const_reference x ) const {
-                       return std::addressof(x);
-               }
-
-               /**
-                * Destroy an item in-place at pointer P.
-                */
-               void destroy(pointer p) {
-                       // destroy using "explicit destructor"
-                       p->~T();
-               }
-
-               // Boilerplate
-               SecureAllocator() {}
-               template<typename U> SecureAllocator(const SecureAllocator<U>&) {}
-               template<typename U> struct rebind { using other = SecureAllocator<U>; };
+template <typename T> class SecureAllocator {
+public:
+  // Type definitions
+  using value_type = T;
+  using pointer = T*;
+  using const_pointer = const T*;
+  using reference = T&;
+  using const_reference = const T&;
+  using size_type = std::size_t;
+  using difference_type = std::ptrdiff_t;
+
+  /**
+   * Allocate memory for N items using the standard allocator.
+   */
+  pointer allocate(size_type n) {
+    // allocate using "global operator new"
+    return static_cast<pointer>(::operator new(n * sizeof(T)));
+  }
+
+  /**
+   * Release memory which was allocated for N items at pointer P.
+   *
+   * The memory block is filled with zeroes before being released.
+   * The pointer argument is tagged as "volatile" to prevent the
+   * compiler optimizing out this critical step.
+   */
+  void deallocate(volatile pointer p, size_type n) {
+    std::memset(p, 0, n * sizeof(T));
+    // free using "global operator delete"
+    ::operator delete(p);
+  }
+
+  /**
+   * Construct an item in-place at pointer P.
+   */
+  template <typename... Args> void construct(pointer p, Args&&... args) {
+    // construct using "placement new" and "perfect forwarding"
+    ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
+  }
+
+  size_type max_size() const { return size_t(-1) / sizeof(T); }
+
+  pointer address(reference x) const { return std::addressof(x); }
+
+  const_pointer address(const_reference x) const { return std::addressof(x); }
+
+  /**
+   * Destroy an item in-place at pointer P.
+   */
+  void destroy(pointer p) {
+    // destroy using "explicit destructor"
+    p->~T();
+  }
+
+  // Boilerplate
+  SecureAllocator() {}
+  template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
+  template <typename U> struct rebind { using other = SecureAllocator<U>; };
 };
 
-
-template<typename T, typename U>
+template <typename T, typename U>
 bool operator==(const SecureAllocator<T>&, const SecureAllocator<U>&) {
-       return true;
+  return true;
 }
 
-template<typename T, typename U>
+template <typename T, typename U>
 bool operator!=(const SecureAllocator<T>&, const SecureAllocator<U>&) {
-       return false;
+  return false;
 }
 
-} //namespace Json
+} // namespace Json
 
 #if !defined(__SUNPRO_CC)
 #pragma pack(pop)
 #endif
 
-#endif // CPPTL_JSON_ALLOCATOR_H_INCLUDED
+#endif // JSON_ALLOCATOR_H_INCLUDED
index f64913f..415c463 100644 (file)
@@ -3,14 +3,14 @@
 // recognized in your jurisdiction.
 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
 
-#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
-#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
+#ifndef JSON_ASSERTIONS_H_INCLUDED
+#define JSON_ASSERTIONS_H_INCLUDED
 
 #if !defined(JSON_IS_AMALGAMATION)
 #include "config.h"
 #endif // if !defined(JSON_IS_AMALGAMATION)
 
-#include <stdlib.h>
+#include <cstdlib>
 #include <sstream>
 
 /** It should not be possible for a maliciously designed file to
 #if JSON_USE_EXCEPTION
 
 // @todo <= add detail about condition in exception
-# define JSON_ASSERT(condition)                                                \
-  {if (!(condition)) {Json::throwLogicError( "assert json failed" );}}
-
-# define JSON_FAIL_MESSAGE(message)                                            \
-  {                                                                            \
-    JSONCPP_OSTRINGSTREAM oss; oss << message;                                    \
+#define JSON_ASSERT(condition)                                                 \
+  do {                                                                         \
+    if (!(condition)) {                                                        \
+      Json::throwLogicError("assert json failed");                             \
+    }                                                                          \
+  } while (0)
+
+#define JSON_FAIL_MESSAGE(message)                                             \
+  do {                                                                         \
+    OStringStream oss;                                                         \
+    oss << message;                                                            \
     Json::throwLogicError(oss.str());                                          \
     abort();                                                                   \
-  }
+  } while (0)
 
 #else // JSON_USE_EXCEPTION
 
-# define JSON_ASSERT(condition) assert(condition)
+#define JSON_ASSERT(condition) assert(condition)
 
 // The call to assert() will show the failure message in debug builds. In
 // release builds we abort, for a core-dump or debugger.
-# define JSON_FAIL_MESSAGE(message)                                            \
+#define JSON_FAIL_MESSAGE(message)                                             \
   {                                                                            \
-    JSONCPP_OSTRINGSTREAM oss; oss << message;                                    \
+    OStringStream oss;                                                         \
+    oss << message;                                                            \
     assert(false && oss.str().c_str());                                        \
     abort();                                                                   \
   }
 
-
 #endif
 
 #define JSON_ASSERT_MESSAGE(condition, message)                                \
-  if (!(condition)) {                                                          \
-    JSON_FAIL_MESSAGE(message);                                                \
-  }
+  do {                                                                         \
+    if (!(condition)) {                                                        \
+      JSON_FAIL_MESSAGE(message);                                              \
+    }                                                                          \
+  } while (0)
 
-#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
+#endif // JSON_ASSERTIONS_H_INCLUDED
index 2cc8462..f03b746 100644 (file)
@@ -6,26 +6,18 @@
 #ifndef JSON_CONFIG_H_INCLUDED
 #define JSON_CONFIG_H_INCLUDED
 
-// Include KWSys Large File Support configuration.
-#include <cmsys/Configure.h>
-
-#include <stddef.h>
-#include <string> //typedef String
-#include <stdint.h> //typedef int64_t, uint64_t
-
 #if defined(_MSC_VER)
 # pragma warning(push,1)
 #endif
 
-/// If defined, indicates that json library is embedded in CppTL library.
-//# define JSON_IN_CPPTL 1
-
-/// If defined, indicates that json may leverage CppTL library
-//#  define JSON_USE_CPPTL 1
-/// If defined, indicates that cpptl vector based map should be used instead of
-/// std::map
-/// as Value container.
-//#  define JSON_USE_CPPTL_SMALLMAP 1
+#include <cstddef>
+#include <cstdint>
+#include <istream>
+#include <memory>
+#include <ostream>
+#include <sstream>
+#include <string>
+#include <type_traits>
 
 // If non-zero, the library uses exceptions to report bad input instead of C
 // assertion macros. The default is to use exceptions.
 #define JSON_USE_EXCEPTION 1
 #endif
 
-/// If defined, indicates that the source file is amalgated
+// Temporary, tracked for removal with issue #982.
+#ifndef JSON_USE_NULLREF
+#define JSON_USE_NULLREF 1
+#endif
+
+/// If defined, indicates that the source file is amalgamated
 /// to prevent private header inclusion.
-/// Remarks: it is automatically defined in the generated amalgated header.
+/// Remarks: it is automatically defined in the generated amalgamated header.
 // #define JSON_IS_AMALGAMATION
 
-#ifdef JSON_IN_CPPTL
-#include <cpptl/config.h>
-#ifndef JSON_USE_CPPTL
-#define JSON_USE_CPPTL 1
-#endif
-#endif
-
-#ifdef JSON_IN_CPPTL
-#define JSON_API CPPTL_API
-#elif defined(JSON_DLL_BUILD)
+// Export macros for DLL visibility
+#if defined(JSON_DLL_BUILD)
 #if defined(_MSC_VER) || defined(__MINGW32__)
 #define JSON_API __declspec(dllexport)
 #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#elif defined(__GNUC__) || defined(__clang__)
+#define JSON_API __attribute__((visibility("default")))
 #endif // if defined(_MSC_VER)
+
 #elif defined(JSON_DLL)
 #if defined(_MSC_VER) || defined(__MINGW32__)
 #define JSON_API __declspec(dllimport)
 #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
 #endif // if defined(_MSC_VER)
-#endif // ifdef JSON_IN_CPPTL
+#endif // ifdef JSON_DLL_BUILD
+
 #if !defined(JSON_API)
 #define JSON_API
 #endif
 
-// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
-// integer
-// Storages, and 64 bits integer support is disabled.
-// #define JSON_NO_INT64 1
+#if defined(_MSC_VER) && _MSC_VER < 1800
+#error                                                                         \
+    "ERROR:  Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities"
+#endif
 
-#if defined(_MSC_VER) // MSVC
-#  if _MSC_VER <= 1200 // MSVC 6
-    // Microsoft Visual Studio 6 only support conversion from __int64 to double
-    // (no conversion from unsigned __int64).
-#    define JSON_USE_INT64_DOUBLE_CONVERSION 1
-    // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
-    // characters in the debug information)
-    // All projects I've ever seen with VS6 were using this globally (not bothering
-    // with pragma push/pop).
-#    pragma warning(disable : 4786)
-#  endif // MSVC 6
-
-#endif // defined(_MSC_VER)
-
-// In c++11 the override keyword allows you to explicity define that a function
-// is intended to override the base-class version.  This makes the code more
-// managable and fixes a set of common hard-to-find bugs.
-#if __cplusplus >= 201103L
-# define JSONCPP_OVERRIDE override
-# define JSONCPP_NOEXCEPT noexcept
-#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900
-# define JSONCPP_OVERRIDE override
-# define JSONCPP_NOEXCEPT throw()
-#elif defined(_MSC_VER) && _MSC_VER >= 1900
-# define JSONCPP_OVERRIDE override
-# define JSONCPP_NOEXCEPT noexcept
+#if defined(_MSC_VER) && _MSC_VER < 1900
+// As recommended at
+// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
+extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
+                                              const char* format, ...);
+#define jsoncpp_snprintf msvc_pre1900_c99_snprintf
 #else
-# define JSONCPP_OVERRIDE
-# define JSONCPP_NOEXCEPT throw()
+#define jsoncpp_snprintf std::snprintf
 #endif
 
-#ifndef JSON_HAS_RVALUE_REFERENCES
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
+// integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
 
-#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010
-#define JSON_HAS_RVALUE_REFERENCES 1
-#endif // MSVC >= 2010
+// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools.
+// C++11 should be used directly in JSONCPP.
+#define JSONCPP_OVERRIDE override
 
 #ifdef __clang__
-#if __has_feature(cxx_rvalue_references)
-#define JSON_HAS_RVALUE_REFERENCES 1
-#endif  // has_feature
-
-#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
-#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
-#define JSON_HAS_RVALUE_REFERENCES 1
-#endif  // GXX_EXPERIMENTAL
-
-#endif // __clang__ || __GNUC__
-
-#endif // not defined JSON_HAS_RVALUE_REFERENCES
-
-#ifndef JSON_HAS_RVALUE_REFERENCES
-#define JSON_HAS_RVALUE_REFERENCES 0
+#if __has_extension(attribute_deprecated_with_message)
+#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
 #endif
-
-#ifdef __clang__
-#  if __has_extension(attribute_deprecated_with_message)
-#    define JSONCPP_DEPRECATED(message)  __attribute__ ((deprecated(message)))
-#  endif
-#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
-#  if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
-#    define JSONCPP_DEPRECATED(message)  __attribute__ ((deprecated(message)))
-#  elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
-#    define JSONCPP_DEPRECATED(message)  __attribute__((__deprecated__))
-#  endif  // GNUC version
-#elif defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008
-    /// Indicates that the following function is deprecated.
-#    define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc)
+#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
+#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
+#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
+#endif                  // GNUC version
+#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates
+                        // MSVC)
+#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
 #endif // __clang__ || __GNUC__ || _MSC_VER
 
 #undef JSONCPP_DEPRECATED // no deprecations in CMake copy
 #define JSONCPP_DEPRECATED(message)
 #endif // if !defined(JSONCPP_DEPRECATED)
 
-#if __GNUC__ >= 6
-#  define JSON_USE_INT64_DOUBLE_CONVERSION 1
+#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6))
+#define JSON_USE_INT64_DOUBLE_CONVERSION 1
 #endif
 
 #if !defined(JSON_IS_AMALGAMATION)
 
-# include "version.h"
-
-# if JSONCPP_USING_SECURE_MEMORY
-#  include "allocator.h" //typedef Allocator
-# endif
+#include "allocator.h"
+#include "version.h"
 
 #endif // if !defined(JSON_IS_AMALGAMATION)
 
 namespace Json {
-typedef int Int;
-typedef unsigned int UInt;
+using Int = int;
+using UInt = unsigned int;
 #if defined(JSON_NO_INT64)
-typedef int LargestInt;
-typedef unsigned int LargestUInt;
+using LargestInt = int;
+using LargestUInt = unsigned int;
 #undef JSON_HAS_INT64
 #else                 // if defined(JSON_NO_INT64)
 // For Microsoft Visual use specific types as long long is not supported
 #if defined(_MSC_VER) // Microsoft Visual Studio
-typedef __int64 Int64;
-typedef unsigned __int64 UInt64;
+using Int64 = __int64;
+using UInt64 = unsigned __int64;
 #else                 // if defined(_MSC_VER) // Other platforms, use long long
-typedef int64_t Int64;
-typedef uint64_t UInt64;
-#endif // if defined(_MSC_VER)
-typedef Int64 LargestInt;
-typedef UInt64 LargestUInt;
+using Int64 = int64_t;
+using UInt64 = uint64_t;
+#endif                // if defined(_MSC_VER)
+using LargestInt = Int64;
+using LargestUInt = UInt64;
 #define JSON_HAS_INT64
 #endif // if defined(JSON_NO_INT64)
-#if JSONCPP_USING_SECURE_MEMORY
-#define JSONCPP_STRING        std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char> >
-#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char> >
-#define JSONCPP_OSTREAM       std::basic_ostream<char, std::char_traits<char>>
-#define JSONCPP_ISTRINGSTREAM std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char> >
-#define JSONCPP_ISTREAM       std::istream
-#else
-#define JSONCPP_STRING        std::string
-#define JSONCPP_OSTRINGSTREAM std::ostringstream
-#define JSONCPP_OSTREAM       std::ostream
-#define JSONCPP_ISTRINGSTREAM std::istringstream
-#define JSONCPP_ISTREAM       std::istream
-#endif // if JSONCPP_USING_SECURE_MEMORY
-} // end namespace Json
+
+template <typename T>
+using Allocator =
+    typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
+                              std::allocator<T>>::type;
+using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
+using IStringStream =
+    std::basic_istringstream<String::value_type, String::traits_type,
+                             String::allocator_type>;
+using OStringStream =
+    std::basic_ostringstream<String::value_type, String::traits_type,
+                             String::allocator_type>;
+using IStream = std::istream;
+using OStream = std::ostream;
+} // namespace Json
+
+// Legacy names (formerly macros).
+using JSONCPP_STRING = Json::String;
+using JSONCPP_ISTRINGSTREAM = Json::IStringStream;
+using JSONCPP_OSTRINGSTREAM = Json::OStringStream;
+using JSONCPP_ISTREAM = Json::IStream;
+using JSONCPP_OSTREAM = Json::OStream;
 
 #endif // JSON_CONFIG_H_INCLUDED
index 70bbe19..affe33a 100644 (file)
 namespace Json {
 
 // writer.h
+class StreamWriter;
+class StreamWriterBuilder;
+class Writer;
 class FastWriter;
 class StyledWriter;
+class StyledStreamWriter;
 
 // reader.h
 class Reader;
+class CharReader;
+class CharReaderBuilder;
 
-// features.h
+// json_features.h
 class Features;
 
 // value.h
-typedef unsigned int ArrayIndex;
+using ArrayIndex = unsigned int;
 class StaticString;
 class Path;
 class PathArgument;
index 5964672..5c776a1 100644 (file)
@@ -6,9 +6,10 @@
 #ifndef JSON_JSON_H_INCLUDED
 #define JSON_JSON_H_INCLUDED
 
-#include "value.h"
+#include "config.h"
+#include "json_features.h"
 #include "reader.h"
+#include "value.h"
 #include "writer.h"
-#include "features.h"
 
 #endif // JSON_JSON_H_INCLUDED
@@ -3,8 +3,8 @@
 // recognized in your jurisdiction.
 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
 
-#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
-#define CPPTL_JSON_FEATURES_H_INCLUDED
+#ifndef JSON_FEATURES_H_INCLUDED
+#define JSON_FEATURES_H_INCLUDED
 
 #if !defined(JSON_IS_AMALGAMATION)
 #include "forwards.h"
@@ -43,17 +43,17 @@ public:
   Features();
 
   /// \c true if comments are allowed. Default: \c true.
-  bool allowComments_;
+  bool allowComments_{true};
 
   /// \c true if root must be either an array or an object value. Default: \c
   /// false.
-  bool strictRoot_;
+  bool strictRoot_{false};
 
   /// \c true if dropped null placeholders are allowed. Default: \c false.
-  bool allowDroppedNullPlaceholders_;
+  bool allowDroppedNullPlaceholders_{false};
 
   /// \c true if numeric object key are allowed. Default: \c false.
-  bool allowNumericKeys_;
+  bool allowNumericKeys_{false};
 };
 
 } // namespace Json
@@ -62,4 +62,4 @@ public:
 #pragma pack(pop)
 #endif
 
-#endif // CPPTL_JSON_FEATURES_H_INCLUDED
+#endif // JSON_FEATURES_H_INCLUDED
index 667246a..7ad0be6 100644 (file)
@@ -3,18 +3,18 @@
 // recognized in your jurisdiction.
 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
 
-#ifndef CPPTL_JSON_READER_H_INCLUDED
-#define CPPTL_JSON_READER_H_INCLUDED
+#ifndef JSON_READER_H_INCLUDED
+#define JSON_READER_H_INCLUDED
 
 #if !defined(JSON_IS_AMALGAMATION)
-#include "features.h"
+#include "json_features.h"
 #include "value.h"
 #endif // if !defined(JSON_IS_AMALGAMATION)
 #include <deque>
 #include <iosfwd>
+#include <istream>
 #include <stack>
 #include <string>
-#include <istream>
 
 // Disable warning C4251: <data member>: <type> needs to have dll-interface to
 // be used by...
 namespace Json {
 
 /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
- *Value.
+ * Value.
  *
  * deprecated Use CharReader and CharReaderBuilder.
  */
-class JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") JSON_API Reader {
+
+class JSONCPP_DEPRECATED(
+    "Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
 public:
-  typedef char Char;
-  typedef const Char* Location;
+  using Char = char;
+  using Location = const Char*;
 
   /** \brief An error tagged with where in the JSON text it was encountered.
    *
    * The offsets give the [start, limit) range of bytes within the text. Note
    * that this is bytes, not codepoints.
-   *
    */
   struct StructuredError {
     ptrdiff_t offset_start;
     ptrdiff_t offset_limit;
-    JSONCPP_STRING message;
+    String message;
   };
 
-  /** \brief Constructs a Reader allowing all features
-   * for parsing.
+  /** \brief Constructs a Reader allowing all features for parsing.
    */
+  JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
   Reader();
 
-  /** \brief Constructs a Reader allowing the specified feature set
-   * for parsing.
+  /** \brief Constructs a Reader allowing the specified feature set for parsing.
    */
+  JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
   Reader(const Features& features);
 
   /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
    * document.
-   * \param document UTF-8 encoded string containing the document to read.
-   * \param root [out] Contains the root value of the document if it was
-   *             successfully parsed.
-   * \param collectComments \c true to collect comment and allow writing them
-   * back during
-   *                        serialization, \c false to discard comments.
-   *                        This parameter is ignored if
-   * Features::allowComments_
-   *                        is \c false.
+   *
+   * \param      document        UTF-8 encoded string containing the document
+   *                             to read.
+   * \param[out] root            Contains the root value of the document if it
+   *                             was successfully parsed.
+   * \param      collectComments \c true to collect comment and allow writing
+   *                             them back during serialization, \c false to
+   *                             discard comments.  This parameter is ignored
+   *                             if Features::allowComments_ is \c false.
    * \return \c true if the document was successfully parsed, \c false if an
    * error occurred.
    */
-  bool
-  parse(const std::string& document, Value& root, bool collectComments = true);
+  bool parse(const std::string& document, Value& root,
+             bool collectComments = true);
 
   /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
-   document.
-   * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
-   document to read.
-   * \param endDoc Pointer on the end of the UTF-8 encoded string of the
-   document to read.
-   *               Must be >= beginDoc.
-   * \param root [out] Contains the root value of the document if it was
-   *             successfully parsed.
-   * \param collectComments \c true to collect comment and allow writing them
-   back during
-   *                        serialization, \c false to discard comments.
-   *                        This parameter is ignored if
-   Features::allowComments_
-   *                        is \c false.
+   * document.
+   *
+   * \param      beginDoc        Pointer on the beginning of the UTF-8 encoded
+   *                             string of the document to read.
+   * \param      endDoc          Pointer on the end of the UTF-8 encoded string
+   *                             of the document to read.  Must be >= beginDoc.
+   * \param[out] root            Contains the root value of the document if it
+   *                             was successfully parsed.
+   * \param      collectComments \c true to collect comment and allow writing
+   *                             them back during serialization, \c false to
+   *                             discard comments.  This parameter is ignored
+   *                             if Features::allowComments_ is \c false.
    * \return \c true if the document was successfully parsed, \c false if an
-   error occurred.
+   error occurred.
    */
-  bool parse(const char* beginDoc,
-             const char* endDoc,
-             Value& root,
+  bool parse(const char* beginDoc, const char* endDoc, Value& root,
              bool collectComments = true);
 
   /// \brief Parse from input stream.
   /// \see Json::operator>>(std::istream&, Json::Value&).
-  bool parse(JSONCPP_ISTREAM& is, Value& root, bool collectComments = true);
+  bool parse(IStream& is, Value& root, bool collectComments = true);
 
   /** \brief Returns a user friendly string that list errors in the parsed
    * document.
-   * \return Formatted error message with the list of errors with their location
-   * in
-   *         the parsed document. An empty string is returned if no error
-   * occurred
-   *         during parsing.
+   *
+   * \return Formatted error message with the list of errors with their
+   * location in the parsed document. An empty string is returned if no error
+   * occurred during parsing.
    * deprecated Use getFormattedErrorMessages() instead (typo fix).
    */
   JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
-  JSONCPP_STRING getFormatedErrorMessages() const;
+  String getFormatedErrorMessages() const;
 
   /** \brief Returns a user friendly string that list errors in the parsed
    * document.
-   * \return Formatted error message with the list of errors with their location
-   * in
-   *         the parsed document. An empty string is returned if no error
-   * occurred
-   *         during parsing.
+   *
+   * \return Formatted error message with the list of errors with their
+   * location in the parsed document. An empty string is returned if no error
+   * occurred during parsing.
    */
-  JSONCPP_STRING getFormattedErrorMessages() const;
+  String getFormattedErrorMessages() const;
 
-  /** \brief Returns a vector of structured erros encounted while parsing.
+  /** \brief Returns a vector of structured errors encountered while parsing.
+   *
    * \return A (possibly empty) vector of StructuredError objects. Currently
-   *         only one error can be returned, but the caller should tolerate
-   * multiple
-   *         errors.  This can occur if the parser recovers from a non-fatal
-   *         parse error and then encounters additional errors.
+   * only one error can be returned, but the caller should tolerate multiple
+   * errors.  This can occur if the parser recovers from a non-fatal parse
+   * error and then encounters additional errors.
    */
   std::vector<StructuredError> getStructuredErrors() const;
 
   /** \brief Add a semantic error message.
-   * \param value JSON Value location associated with the error
+   *
+   * \param value   JSON Value location associated with the error
    * \param message The error message.
-   * \return \c true if the error was successfully added, \c false if the
-   * Value offset exceeds the document size.
+   * \return \c true if the error was successfully added, \c false if the Value
+   * offset exceeds the document size.
    */
-  bool pushError(const Value& value, const JSONCPP_STRING& message);
+  bool pushError(const Value& value, const String& message);
 
   /** \brief Add a semantic error message with extra context.
-   * \param value JSON Value location associated with the error
+   *
+   * \param value   JSON Value location associated with the error
    * \param message The error message.
-   * \param extra Additional JSON Value location to contextualize the error
+   * \param extra   Additional JSON Value location to contextualize the error
    * \return \c true if the error was successfully added, \c false if either
    * Value offset exceeds the document size.
    */
-  bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra);
+  bool pushError(const Value& value, const String& message, const Value& extra);
 
   /** \brief Return whether there are any errors.
-   * \return \c true if there are no errors to report \c false if
-   * errors have occurred.
+   *
+   * \return \c true if there are no errors to report \c false if errors have
+   * occurred.
    */
   bool good() const;
 
@@ -187,15 +185,15 @@ private:
   class ErrorInfo {
   public:
     Token token_;
-    JSONCPP_STRING message_;
+    String message_;
     Location extra_;
   };
 
-  typedef std::deque<ErrorInfo> Errors;
+  using Errors = std::deque<ErrorInfo>;
 
   bool readToken(Token& token);
   void skipSpaces();
-  bool match(Location pattern, int patternLength);
+  bool match(const Char* pattern, int patternLength);
   bool readComment();
   bool readCStyleComment();
   bool readCppStyleComment();
@@ -207,142 +205,138 @@ private:
   bool decodeNumber(Token& token);
   bool decodeNumber(Token& token, Value& decoded);
   bool decodeString(Token& token);
-  bool decodeString(Token& token, JSONCPP_STRING& decoded);
+  bool decodeString(Token& token, String& decoded);
   bool decodeDouble(Token& token);
   bool decodeDouble(Token& token, Value& decoded);
-  bool decodeUnicodeCodePoint(Token& token,
-                              Location& current,
-                              Location end,
+  bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
                               unsigned int& unicode);
-  bool decodeUnicodeEscapeSequence(Token& token,
-                                   Location& current,
-                                   Location end,
-                                   unsigned int& unicode);
-  bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0);
+  bool decodeUnicodeEscapeSequence(Token& token, Location& current,
+                                   Location end, unsigned int& unicode);
+  bool addError(const String& message, Token& token, Location extra = nullptr);
   bool recoverFromError(TokenType skipUntilToken);
-  bool addErrorAndRecover(const JSONCPP_STRING& message,
-                          Token& token,
+  bool addErrorAndRecover(const String& message, Token& token,
                           TokenType skipUntilToken);
   void skipUntilSpace();
   Value& currentValue();
   Char getNextChar();
-  void
-  getLocationLineAndColumn(Location location, int& line, int& column) const;
-  JSONCPP_STRING getLocationLineAndColumn(Location location) const;
+  void getLocationLineAndColumn(Location location, int& line,
+                                int& column) const;
+  String getLocationLineAndColumn(Location location) const;
   void addComment(Location begin, Location end, CommentPlacement placement);
   void skipCommentTokens(Token& token);
 
   static bool containsNewLine(Location begin, Location end);
-  static JSONCPP_STRING normalizeEOL(Location begin, Location end);
+  static String normalizeEOL(Location begin, Location end);
 
-  typedef std::stack<Value*> Nodes;
+  using Nodes = std::stack<Value*>;
   Nodes nodes_;
   Errors errors_;
-  JSONCPP_STRING document_;
-  Location begin_;
-  Location end_;
-  Location current_;
-  Location lastValueEnd_;
-  Value* lastValue_;
-  JSONCPP_STRING commentsBefore_;
+  String document_;
+  Location begin_{};
+  Location end_{};
+  Location current_{};
+  Location lastValueEnd_{};
+  Value* lastValue_{};
+  String commentsBefore_;
   Features features_;
-  bool collectComments_;
-};  // Reader
+  bool collectComments_{};
+}; // Reader
 
 /** Interface for reading JSON from a char array.
  */
 class JSON_API CharReader {
 public:
-  virtual ~CharReader() {}
+  virtual ~CharReader() = default;
   /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
-   document.
-   * The document must be a UTF-8 encoded string containing the document to read.
+   * document. The document must be a UTF-8 encoded string containing the
+   * document to read.
    *
-   * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
-   document to read.
-   * \param endDoc Pointer on the end of the UTF-8 encoded string of the
-   document to read.
-   *        Must be >= beginDoc.
-   * \param root [out] Contains the root value of the document if it was
-   *             successfully parsed.
-   * \param errs [out] Formatted error messages (if not NULL)
-   *        a user friendly string that lists errors in the parsed
-   * document.
+   * \param      beginDoc Pointer on the beginning of the UTF-8 encoded string
+   *                      of the document to read.
+   * \param      endDoc   Pointer on the end of the UTF-8 encoded string of the
+   *                      document to read. Must be >= beginDoc.
+   * \param[out] root     Contains the root value of the document if it was
+   *                      successfully parsed.
+   * \param[out] errs     Formatted error messages (if not NULL) a user
+   *                      friendly string that lists errors in the parsed
+   *                      document.
    * \return \c true if the document was successfully parsed, \c false if an
-   error occurred.
+   error occurred.
    */
-  virtual bool parse(
-      char const* beginDoc, char const* endDoc,
-      Value* root, JSONCPP_STRING* errs) = 0;
+  virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
+                     String* errs) = 0;
 
   class JSON_API Factory {
   public:
-    virtual ~Factory() {}
+    virtual ~Factory() = default;
     /** \brief Allocate a CharReader via operator new().
      * \throw std::exception if something goes wrong (e.g. invalid settings)
      */
     virtual CharReader* newCharReader() const = 0;
-  };  // Factory
-};  // CharReader
+  }; // Factory
+};   // CharReader
 
 /** \brief Build a CharReader implementation.
-
-Usage:
-\code
-  using namespace Json;
-  CharReaderBuilder builder;
-  builder["collectComments"] = false;
-  Value value;
 JSONCPP_STRING errs;
-  bool ok = parseFromStream(builder, std::cin, &value, &errs);
-\endcode
-*/
+ *
+ * Usage:
+ *   \code
*   using namespace Json;
*   CharReaderBuilder builder;
*   builder["collectComments"] = false;
*   Value value;
*   String errs;
*   bool ok = parseFromStream(builder, std::cin, &value, &errs);
+ *   \endcode
+ */
 class JSON_API CharReaderBuilder : public CharReader::Factory {
 public:
   // Note: We use a Json::Value so that we can add data-members to this class
   // without a major version bump.
   /** Configuration of this builder.
-    These are case-sensitive.
-    Available settings (case-sensitive):
-    - `"collectComments": false or true`
-      - true to collect comment and allow writing them
-        back during serialization, false to discard comments.
-        This parameter is ignored if allowComments is false.
-    - `"allowComments": false or true`
-      - true if comments are allowed.
-    - `"strictRoot": false or true`
-      - true if root must be either an array or an object value
-    - `"allowDroppedNullPlaceholders": false or true`
-      - true if dropped null placeholders are allowed. (See StreamWriterBuilder.)
-    - `"allowNumericKeys": false or true`
-      - true if numeric object keys are allowed.
-    - `"allowSingleQuotes": false or true`
-      - true if '' are allowed for strings (both keys and values)
-    - `"stackLimit": integer`
-      - Exceeding stackLimit (recursive depth of `readValue()`) will
-        cause an exception.
-      - This is a security issue (seg-faults caused by deeply nested JSON),
-        so the default is low.
-    - `"failIfExtra": false or true`
-      - If true, `parse()` returns false when extra non-whitespace trails
-        the JSON value in the input string.
-    - `"rejectDupKeys": false or true`
-      - If true, `parse()` returns false when a key is duplicated within an object.
-    - `"allowSpecialFloats": false or true`
-      - If true, special float values (NaNs and infinities) are allowed 
-        and their values are lossfree restorable.
-
-    You can examine 'settings_` yourself
-    to see the defaults. You can also write and read them just like any
-    JSON Value.
-    \sa setDefaults()
-    */
+   * These are case-sensitive.
+   * Available settings (case-sensitive):
+   * - `"collectComments": false or true`
+   *   - true to collect comment and allow writing them back during
+   *     serialization, false to discard comments.  This parameter is ignored
+   *     if allowComments is false.
+   * - `"allowComments": false or true`
+   *   - true if comments are allowed.
+   * - `"allowTrailingCommas": false or true`
+   *   - true if trailing commas in objects and arrays are allowed.
+   * - `"strictRoot": false or true`
+   *   - true if root must be either an array or an object value
+   * - `"allowDroppedNullPlaceholders": false or true`
+   *   - true if dropped null placeholders are allowed. (See
+   *     StreamWriterBuilder.)
+   * - `"allowNumericKeys": false or true`
+   *   - true if numeric object keys are allowed.
+   * - `"allowSingleQuotes": false or true`
+   *   - true if '' are allowed for strings (both keys and values)
+   * - `"stackLimit": integer`
+   *   - Exceeding stackLimit (recursive depth of `readValue()`) will cause an
+   *     exception.
+   *   - This is a security issue (seg-faults caused by deeply nested JSON), so
+   *     the default is low.
+   * - `"failIfExtra": false or true`
+   *   - If true, `parse()` returns false when extra non-whitespace trails the
+   *     JSON value in the input string.
+   * - `"rejectDupKeys": false or true`
+   *   - If true, `parse()` returns false when a key is duplicated within an
+   *     object.
+   * - `"allowSpecialFloats": false or true`
+   *   - If true, special float values (NaNs and infinities) are allowed and
+   *     their values are lossfree restorable.
+   *
+   * You can examine 'settings_` yourself to see the defaults. You can also
+   * write and read them just like any JSON Value.
+   * \sa setDefaults()
+   */
   Json::Value settings_;
 
   CharReaderBuilder();
-  ~CharReaderBuilder() JSONCPP_OVERRIDE;
+  ~CharReaderBuilder() override;
 
-  CharReader* newCharReader() const JSONCPP_OVERRIDE;
+  CharReader* newCharReader() const override;
 
   /** \return true if 'settings' are legal and consistent;
    *   otherwise, indicate bad settings via 'invalid'.
@@ -351,7 +345,7 @@ public:
 
   /** A simple way to update a specific setting.
    */
-  Value& operator[](JSONCPP_STRING key);
+  Value& operator[](const String& key);
 
   /** Called by ctor, but you can use this to reset settings_.
    * \pre 'settings' != NULL (but Json::null is fine)
@@ -368,39 +362,37 @@ public:
 };
 
 /** Consume entire stream and use its begin/end.
-  * Someday we might have a real StreamReader, but for now this
-  * is convenient.
-  */
-bool JSON_API parseFromStream(
-    CharReader::Factory const&,
-    JSONCPP_ISTREAM&,
-    Value* root, std::string* errs);
+ * Someday we might have a real StreamReader, but for now this
+ * is convenient.
+ */
+bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root,
+                              String* errs);
 
 /** \brief Read from 'sin' into 'root'.
-
- Always keep comments from the input JSON.
-
- This can be used to read a file into a particular sub-object.
- For example:
- \code
- Json::Value root;
- cin >> root["dir"]["file"];
- cout << root;
- \endcode
- Result:
- \verbatim
- {
- "dir": {
-     "file": {
-     // The input stream JSON would be nested here.
-     }
- }
- }
- \endverbatim
- \throw std::exception on parse error.
- \see Json::operator<<()
-*/
-JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&);
+ *
Always keep comments from the input JSON.
+ *
This can be used to read a file into a particular sub-object.
For example:
*   \code
*   Json::Value root;
*   cin >> root["dir"]["file"];
*   cout << root;
*   \endcode
Result:
\verbatim
{
"dir": {
*    "file": {
*    // The input stream JSON would be nested here.
*    }
}
}
\endverbatim
\throw std::exception on parse error.
\see Json::operator<<()
+ */
+JSON_API IStream& operator>>(IStream&, Value&);
 
 } // namespace Json
 
@@ -412,4 +404,4 @@ JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&);
 #pragma warning(pop)
 #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
 
-#endif // CPPTL_JSON_READER_H_INCLUDED
+#endif // JSON_READER_H_INCLUDED
index 7b90c5a..952d423 100644 (file)
@@ -3,38 +3,49 @@
 // recognized in your jurisdiction.
 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
 
-#ifndef CPPTL_JSON_H_INCLUDED
-#define CPPTL_JSON_H_INCLUDED
+#ifndef JSON_H_INCLUDED
+#define JSON_H_INCLUDED
 
 #if !defined(JSON_IS_AMALGAMATION)
 #include "forwards.h"
 #endif // if !defined(JSON_IS_AMALGAMATION)
-#include <string>
-#include <vector>
-#include <exception>
 
-#ifndef JSON_USE_CPPTL_SMALLMAP
-#include <map>
+// Conditional NORETURN attribute on the throw functions would:
+// a) suppress false positives from static code analysis
+// b) possibly improve optimization opportunities.
+#if !defined(JSONCPP_NORETURN)
+#if defined(_MSC_VER) && _MSC_VER == 1800
+#define JSONCPP_NORETURN __declspec(noreturn)
 #else
-#include <cpptl/smallmap.h>
+#define JSONCPP_NORETURN [[noreturn]]
 #endif
-#ifdef JSON_USE_CPPTL
-#include <cpptl/forwards.h>
 #endif
 
-//Conditional NORETURN attribute on the throw functions would:
-// a) suppress false positives from static code analysis
-// b) possibly improve optimization opportunities.
-#if !defined(JSONCPP_NORETURN)
-#  if defined(_MSC_VER)
-#    define JSONCPP_NORETURN __declspec(noreturn)
-#  elif defined(__GNUC__)
-#    define JSONCPP_NORETURN __attribute__ ((__noreturn__))
-#  else
-#    define JSONCPP_NORETURN
-#  endif
+// Support for '= delete' with template declarations was a late addition
+// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2
+// even though these declare themselves to be c++11 compilers.
+#if !defined(JSONCPP_TEMPLATE_DELETE)
+#if defined(__clang__) && defined(__apple_build_version__)
+#if __apple_build_version__ <= 8000042
+#define JSONCPP_TEMPLATE_DELETE
+#endif
+#elif defined(__clang__)
+#if __clang_major__ == 3 && __clang_minor__ <= 8
+#define JSONCPP_TEMPLATE_DELETE
+#endif
+#endif
+#if !defined(JSONCPP_TEMPLATE_DELETE)
+#define JSONCPP_TEMPLATE_DELETE = delete
+#endif
 #endif
 
+#include <array>
+#include <exception>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
 // Disable warning C4251: <data member>: <type> needs to have dll-interface to
 // be used by...
 #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
  */
 namespace Json {
 
+#if JSON_USE_EXCEPTION
 /** Base class for all exceptions we throw.
  *
  * We use nothing but these internally. Of course, STL can throw others.
  */
 class JSON_API Exception : public std::exception {
 public:
-  Exception(JSONCPP_STRING const& msg);
-  ~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE;
-  char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE;
+  Exception(String msg);
+  ~Exception() noexcept override;
+  char const* what() const noexcept override;
+
 protected:
-  JSONCPP_STRING msg_;
+  String msg_;
 };
 
 /** Exceptions which the user cannot easily avoid.
@@ -71,7 +84,7 @@ protected:
  */
 class JSON_API RuntimeError : public Exception {
 public:
-  RuntimeError(JSONCPP_STRING const& msg);
+  RuntimeError(String const& msg);
 };
 
 /** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
@@ -82,13 +95,14 @@ public:
  */
 class JSON_API LogicError : public Exception {
 public:
-  LogicError(JSONCPP_STRING const& msg);
+  LogicError(String const& msg);
 };
+#endif
 
 /// used internally
-JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg);
+JSONCPP_NORETURN void throwRuntimeError(String const& msg);
 /// used internally
-JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg);
+JSONCPP_NORETURN void throwLogicError(String const& msg);
 
 /** \brief Type of the value held by a Value object.
  */
@@ -111,14 +125,16 @@ enum CommentPlacement {
   numberOfCommentPlacement
 };
 
-//# ifdef JSON_USE_CPPTL
-//   typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
-//   typedef CppTL::AnyEnumerator<const Value &> EnumValues;
-//# endif
+/** \brief Type of precision for formatting of real values.
+ */
+enum PrecisionType {
+  significantDigits = 0, ///< we set max number of significant digits in string
+  decimalPlaces          ///< we set max number of digits after "." in string
+};
 
 /** \brief Lightweight wrapper to tag static string.
  *
- * Value constructor and objectValue member assignement takes advantage of the
+ * Value constructor and objectValue member assignment takes advantage of the
  * StaticString and avoid the cost of string duplication when storing the
  * string or the member name.
  *
@@ -167,7 +183,7 @@ private:
  * The get() methods can be used to obtain default value in the case the
  * required element does not exist.
  *
- * It is possible to iterate over the list of a #objectValue values using
+ * It is possible to iterate over the list of member keys of an object using
  * the getMemberNames() method.
  *
  * \note #Value string-length fit in size_t, but keys must be < 2^30.
@@ -178,73 +194,86 @@ private:
  */
 class JSON_API Value {
   friend class ValueIteratorBase;
+
 public:
-  typedef std::vector<JSONCPP_STRING> Members;
-  typedef ValueIterator iterator;
-  typedef ValueConstIterator const_iterator;
-  typedef Json::UInt UInt;
-  typedef Json::Int Int;
+  using Members = std::vector<String>;
+  using iterator = ValueIterator;
+  using const_iterator = ValueConstIterator;
+  using UInt = Json::UInt;
+  using Int = Json::Int;
 #if defined(JSON_HAS_INT64)
-  typedef Json::UInt64 UInt64;
-  typedef Json::Int64 Int64;
+  using UInt64 = Json::UInt64;
+  using Int64 = Json::Int64;
 #endif // defined(JSON_HAS_INT64)
-  typedef Json::LargestInt LargestInt;
-  typedef Json::LargestUInt LargestUInt;
-  typedef Json::ArrayIndex ArrayIndex;
+  using LargestInt = Json::LargestInt;
+  using LargestUInt = Json::LargestUInt;
+  using ArrayIndex = Json::ArrayIndex;
 
-  static const Value& null;  ///< We regret this reference to a global instance; prefer the simpler Value().
-  static const Value& nullRef;  ///< just a kludge for binary-compatibility; same as null
-  static Value const& nullSingleton(); ///< Prefer this to null or nullRef.
+  // Required for boost integration, e. g. BOOST_TEST
+  using value_type = std::string;
+
+#if JSON_USE_NULLREF
+  // Binary compatibility kludges, do not use.
+  static const Value& null;
+  static const Value& nullRef;
+#endif
+
+  // null and nullRef are deprecated, use this instead.
+  static Value const& nullSingleton();
 
   /// Minimum signed integer value that can be stored in a Json::Value.
-  static const LargestInt minLargestInt;
+  static constexpr LargestInt minLargestInt =
+      LargestInt(~(LargestUInt(-1) / 2));
   /// Maximum signed integer value that can be stored in a Json::Value.
-  static const LargestInt maxLargestInt;
+  static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2);
   /// Maximum unsigned integer value that can be stored in a Json::Value.
-  static const LargestUInt maxLargestUInt;
+  static constexpr LargestUInt maxLargestUInt = LargestUInt(-1);
 
   /// Minimum signed int value that can be stored in a Json::Value.
-  static const Int minInt;
+  static constexpr Int minInt = Int(~(UInt(-1) / 2));
   /// Maximum signed int value that can be stored in a Json::Value.
-  static const Int maxInt;
+  static constexpr Int maxInt = Int(UInt(-1) / 2);
   /// Maximum unsigned int value that can be stored in a Json::Value.
-  static const UInt maxUInt;
+  static constexpr UInt maxUInt = UInt(-1);
 
 #if defined(JSON_HAS_INT64)
   /// Minimum signed 64 bits int value that can be stored in a Json::Value.
-  static const Int64 minInt64;
+  static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2));
   /// Maximum signed 64 bits int value that can be stored in a Json::Value.
-  static const Int64 maxInt64;
+  static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2);
   /// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
-  static const UInt64 maxUInt64;
+  static constexpr UInt64 maxUInt64 = UInt64(-1);
 #endif // defined(JSON_HAS_INT64)
-
+  /// Default precision for real value for string representation.
+  static constexpr UInt defaultRealPrecision = 17;
+  // The constant is hard-coded because some compiler have trouble
+  // converting Value::maxUInt64 to a double correctly (AIX/xlC).
+  // Assumes that UInt64 is a 64 bits integer.
+  static constexpr double maxUInt64AsDouble = 18446744073709551615.0;
+// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler
+// when using gcc and clang backend compilers.  CZString
+// cannot be defined as private.  See issue #486
+#ifdef __NVCC__
+public:
+#else
 private:
+#endif
 #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
   class CZString {
   public:
-    enum DuplicationPolicy {
-      noDuplication = 0,
-      duplicate,
-      duplicateOnCopy
-    };
+    enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy };
     CZString(ArrayIndex index);
     CZString(char const* str, unsigned length, DuplicationPolicy allocate);
     CZString(CZString const& other);
-#if JSON_HAS_RVALUE_REFERENCES
     CZString(CZString&& other);
-#endif
     ~CZString();
     CZString& operator=(const CZString& other);
-
-#if JSON_HAS_RVALUE_REFERENCES
     CZString& operator=(CZString&& other);
-#endif
 
     bool operator<(CZString const& other) const;
     bool operator==(CZString const& other) const;
     ArrayIndex index() const;
-    //const char* c_str() const; ///< deprecated
+    // const char* c_str() const; ///< deprecated
     char const* data() const;
     unsigned length() const;
     bool isStaticString() const;
@@ -253,11 +282,11 @@ private:
     void swap(CZString& other);
 
     struct StringStorage {
-      unsigned policy_: 2;
-      unsigned length_: 30; // 1GB max
+      unsigned policy_ : 2;
+      unsigned length_ : 30; // 1GB max
     };
 
-    char const* cstr_;  // actually, a prefixed string, unless policy is noDup
+    char const* cstr_; // actually, a prefixed string, unless policy is noDup
     union {
       ArrayIndex index_;
       StringStorage storage_;
@@ -265,29 +294,26 @@ private:
   };
 
 public:
-#ifndef JSON_USE_CPPTL_SMALLMAP
   typedef std::map<CZString, Value> ObjectValues;
-#else
-  typedef CppTL::SmallMap<CZString, Value> ObjectValues;
-#endif // ifndef JSON_USE_CPPTL_SMALLMAP
 #endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
 
 public:
-  /** \brief Create a default Value of the given type.
-
-    This is a very useful constructor.
-    To create an empty array, pass arrayValue.
-    To create an empty object, pass objectValue.
-    Another Value can then be set to this one by assignment.
-This is useful since clear() and resize() will not alter types.
-
-    Examples:
-\code
-Json::Value null_value; // null
-Json::Value arr_value(Json::arrayValue); // []
-Json::Value obj_value(Json::objectValue); // {}
-\endcode
-  */
+  /**
+   * \brief Create a default Value of the given type.
+   *
+   * This is a very useful constructor.
+   * To create an empty array, pass arrayValue.
+   * To create an empty object, pass objectValue.
+   * Another Value can then be set to this one by assignment.
+   * This is useful since clear() and resize() will not alter types.
+   *
+   * Examples:
+   *   \code
+   *   Json::Value null_value; // null
+   *   Json::Value arr_value(Json::arrayValue); // []
+   *   Json::Value obj_value(Json::objectValue); // {}
+   *   \endcode
+   */
   Value(ValueType type = nullValue);
   Value(Int value);
   Value(UInt value);
@@ -298,38 +324,35 @@ Json::Value obj_value(Json::objectValue); // {}
   Value(double value);
   Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.)
   Value(const char* begin, const char* end); ///< Copy all, incl zeroes.
-  /** \brief Constructs a value from a static string.
-
+  /**
+   * \brief Constructs a value from a static string.
+   *
    * Like other value string constructor but do not duplicate the string for
-   * internal storage. The given string must remain alive after the call to this
-   * constructor.
+   * internal storage. The given string must remain alive after the call to
+   * this constructor.
+   *
    * \note This works only for null-terminated strings. (We cannot change the
-   *   size of this class, so we have nowhere to store the length,
-   *   which might be computed later for various operations.)
+   * size of this class, so we have nowhere to store the length, which might be
+   * computed later for various operations.)
    *
    * Example of usage:
-   * \code
-   * static StaticString foo("some text");
-   * Json::Value aValue(foo);
-   * \endcode
+   *   \code
+   *   static StaticString foo("some text");
+   *   Json::Value aValue(foo);
+   *   \endcode
    */
   Value(const StaticString& value);
-  Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded zeroes too.
-#ifdef JSON_USE_CPPTL
-  Value(const CppTL::ConstString& value);
-#endif
+  Value(const String& value);
   Value(bool value);
-  /// Deep copy.
+  Value(std::nullptr_t ptr) = delete;
   Value(const Value& other);
-#if JSON_HAS_RVALUE_REFERENCES
-  /// Move constructor
   Value(Value&& other);
-#endif
   ~Value();
 
-  /// Deep copy, then swap(other).
-  /// \note Over-write existing comments. To preserve comments, use #swapPayload().
-  Value& operator=(Value other);
+  /// \note Overwrite existing comments. To preserve comments, use
+  /// #swapPayload().
+  Value& operator=(const Value& other);
+  Value& operator=(Value&& other);
 
   /// Swap everything.
   void swap(Value& other);
@@ -354,17 +377,14 @@ Json::Value obj_value(Json::objectValue); // {}
 
   const char* asCString() const; ///< Embedded zeroes could cause you trouble!
 #if JSONCPP_USING_SECURE_MEMORY
-  unsigned getCStringLength() const; //Allows you to understand the length of the CString
+  unsigned getCStringLength() const; // Allows you to understand the length of
+                                     // the CString
 #endif
-  JSONCPP_STRING asString() const; ///< Embedded zeroes are possible.
+  String asString() const; ///< Embedded zeroes are possible.
   /** Get raw char* of string-value.
    *  \return false if !string. (Seg-fault if str or end are NULL.)
    */
-  bool getString(
-      char const** begin, char const** end) const;
-#ifdef JSON_USE_CPPTL
-  CppTL::ConstString asConstString() const;
-#endif
+  bool getString(char const** begin, char const** end) const;
   Int asInt() const;
   UInt asUInt() const;
 #if defined(JSON_HAS_INT64)
@@ -390,6 +410,10 @@ Json::Value obj_value(Json::objectValue); // {}
   bool isArray() const;
   bool isObject() const;
 
+  /// The `as<T>` and `is<T>` member function templates and specializations.
+  template <typename T> T as() const JSONCPP_TEMPLATE_DELETE;
+  template <typename T> bool is() const JSONCPP_TEMPLATE_DELETE;
+
   bool isConvertibleTo(ValueType other) const;
 
   /// Number of values in array or object
@@ -399,50 +423,41 @@ Json::Value obj_value(Json::objectValue); // {}
   /// otherwise, false.
   bool empty() const;
 
-  /// Return isNull()
-  bool operator!() const;
+  /// Return !isNull()
+  explicit operator bool() const;
 
   /// Remove all object members and array elements.
   /// \pre type() is arrayValue, objectValue, or nullValue
   /// \post type() is unchanged
   void clear();
 
-  /// Resize the array to size elements.
+  /// Resize the array to newSize elements.
   /// New elements are initialized to null.
   /// May only be called on nullValue or arrayValue.
   /// \pre type() is arrayValue or nullValue
   /// \post type() is arrayValue
-  void resize(ArrayIndex size);
+  void resize(ArrayIndex newSize);
 
-  /// Access an array element (zero based index ).
-  /// If the array contains less than index element, then null value are
-  /// inserted
-  /// in the array so that its size is index+1.
+  //@{
+  /// Access an array element (zero based index). If the array contains less
+  /// than index element, then null value are inserted in the array so that
+  /// its size is index+1.
   /// (You may need to say 'value[0u]' to get your compiler to distinguish
-  ///  this from the operator[] which takes a string.)
+  /// this from the operator[] which takes a string.)
   Value& operator[](ArrayIndex index);
-
-  /// Access an array element (zero based index ).
-  /// If the array contains less than index element, then null value are
-  /// inserted
-  /// in the array so that its size is index+1.
-  /// (You may need to say 'value[0u]' to get your compiler to distinguish
-  ///  this from the operator[] which takes a string.)
   Value& operator[](int index);
+  //@}
 
-  /// Access an array element (zero based index )
+  //@{
+  /// Access an array element (zero based index).
   /// (You may need to say 'value[0u]' to get your compiler to distinguish
-  ///  this from the operator[] which takes a string.)
+  /// this from the operator[] which takes a string.)
   const Value& operator[](ArrayIndex index) const;
-
-  /// Access an array element (zero based index )
-  /// (You may need to say 'value[0u]' to get your compiler to distinguish
-  ///  this from the operator[] which takes a string.)
   const Value& operator[](int index) const;
+  //@}
 
   /// If the array contains at least index+1 elements, returns the element
-  /// value,
-  /// otherwise returns defaultValue.
+  /// value, otherwise returns defaultValue.
   Value get(ArrayIndex index, const Value& defaultValue) const;
   /// Return true if index < size().
   bool isValidIndex(ArrayIndex index) const;
@@ -450,61 +465,51 @@ Json::Value obj_value(Json::objectValue); // {}
   ///
   /// Equivalent to jsonvalue[jsonvalue.size()] = value;
   Value& append(const Value& value);
-
-#if JSON_HAS_RVALUE_REFERENCES
   Value& append(Value&& value);
-#endif
+
+  /// \brief Insert value in array at specific index
+  bool insert(ArrayIndex index, const Value& newValue);
+  bool insert(ArrayIndex index, Value&& newValue);
 
   /// Access an object value by name, create a null member if it does not exist.
   /// \note Because of our implementation, keys are limited to 2^30 -1 chars.
-  ///  Exceeding that will cause an exception.
+  /// Exceeding that will cause an exception.
   Value& operator[](const char* key);
   /// Access an object value by name, returns null if there is no member with
   /// that name.
   const Value& operator[](const char* key) const;
   /// Access an object value by name, create a null member if it does not exist.
   /// \param key may contain embedded nulls.
-  Value& operator[](const JSONCPP_STRING& key);
+  Value& operator[](const String& key);
   /// Access an object value by name, returns null if there is no member with
   /// that name.
   /// \param key may contain embedded nulls.
-  const Value& operator[](const JSONCPP_STRING& key) const;
+  const Value& operator[](const String& key) const;
   /** \brief Access an object value by name, create a null member if it does not
-   exist.
-
-   * If the object has no entry for that name, then the member name used to store
-   * the new entry is not duplicated.
+   exist.
+   *
+   * If the object has no entry for that name, then the member name used to
+   * store the new entry is not duplicated.
    * Example of use:
-   * \code
-   * Json::Value object;
-   * static const StaticString code("code");
-   * object[code] = 1234;
-   * \endcode
+   *   \code
+   *   Json::Value object;
+   *   static const StaticString code("code");
+   *   object[code] = 1234;
+   *   \endcode
    */
   Value& operator[](const StaticString& key);
-#ifdef JSON_USE_CPPTL
-  /// Access an object value by name, create a null member if it does not exist.
-  Value& operator[](const CppTL::ConstString& key);
-  /// Access an object value by name, returns null if there is no member with
-  /// that name.
-  const Value& operator[](const CppTL::ConstString& key) const;
-#endif
   /// Return the member named key if it exist, defaultValue otherwise.
   /// \note deep copy
   Value get(const char* key, const Value& defaultValue) const;
   /// Return the member named key if it exist, defaultValue otherwise.
   /// \note deep copy
   /// \note key may contain embedded nulls.
-  Value get(const char* begin, const char* end, const Value& defaultValue) const;
+  Value get(const char* begin, const char* end,
+            const Value& defaultValue) const;
   /// Return the member named key if it exist, defaultValue otherwise.
   /// \note deep copy
   /// \param key may contain embedded nulls.
-  Value get(const JSONCPP_STRING& key, const Value& defaultValue) const;
-#ifdef JSON_USE_CPPTL
-  /// Return the member named key if it exist, defaultValue otherwise.
-  /// \note deep copy
-  Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
-#endif
+  Value get(const String& key, const Value& defaultValue) const;
   /// Most general and efficient version of isMember()const, get()const,
   /// and operator[]const
   /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
@@ -512,53 +517,44 @@ Json::Value obj_value(Json::objectValue); // {}
   /// Most general and efficient version of object-mutators.
   /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
   /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
-  Value const* demand(char const* begin, char const* end);
+  Value* demand(char const* begin, char const* end);
   /// \brief Remove and return the named member.
   ///
   /// Do nothing if it did not exist.
-  /// \return the removed Value, or null.
   /// \pre type() is objectValue or nullValue
   /// \post type() is unchanged
-  /// deprecated
-  JSONCPP_DEPRECATED("")
-  Value removeMember(const char* key);
+  void removeMember(const char* key);
   /// Same as removeMember(const char*)
   /// \param key may contain embedded nulls.
-  /// deprecated
-  JSONCPP_DEPRECATED("")
-  Value removeMember(const JSONCPP_STRING& key);
+  void removeMember(const String& key);
   /// Same as removeMember(const char* begin, const char* end, Value* removed),
   /// but 'key' is null-terminated.
   bool removeMember(const char* key, Value* removed);
   /** \brief Remove the named map member.
-
-      Update 'removed' iff removed.
-      \param key may contain embedded nulls.
-      \return true iff removed (no exceptions)
-  */
-  bool removeMember(JSONCPP_STRING const& key, Value* removed);
-  /// Same as removeMember(JSONCPP_STRING const& key, Value* removed)
+   *
+   *  Update 'removed' iff removed.
+   *  \param key may contain embedded nulls.
+   *  \return true iff removed (no exceptions)
+   */
+  bool removeMember(String const& key, Value* removed);
+  /// Same as removeMember(String const& key, Value* removed)
   bool removeMember(const char* begin, const char* end, Value* removed);
   /** \brief Remove the indexed array element.
-
-      O(n) expensive operations.
-      Update 'removed' iff removed.
-      \return true iff removed (no exceptions)
-  */
-  bool removeIndex(ArrayIndex i, Value* removed);
+   *
+   *  O(n) expensive operations.
+   *  Update 'removed' iff removed.
+   *  \return true if removed (no exceptions)
+   */
+  bool removeIndex(ArrayIndex index, Value* removed);
 
   /// Return true if the object has a member named key.
   /// \note 'key' must be null-terminated.
   bool isMember(const char* key) const;
   /// Return true if the object has a member named key.
   /// \param key may contain embedded nulls.
-  bool isMember(const JSONCPP_STRING& key) const;
-  /// Same as isMember(JSONCPP_STRING const& key)const
+  bool isMember(const String& key) const;
+  /// Same as isMember(String const& key)const
   bool isMember(const char* begin, const char* end) const;
-#ifdef JSON_USE_CPPTL
-  /// Return true if the object has a member named key.
-  bool isMember(const CppTL::ConstString& key) const;
-#endif
 
   /// \brief Return a list of the member names.
   ///
@@ -567,23 +563,22 @@ Json::Value obj_value(Json::objectValue); // {}
   /// \post if type() was nullValue, it remains nullValue
   Members getMemberNames() const;
 
-  //# ifdef JSON_USE_CPPTL
-  //      EnumMemberNames enumMemberNames() const;
-  //      EnumValues enumValues() const;
-  //# endif
-
   /// deprecated Always pass len.
-  JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.")
-  void setComment(const char* comment, CommentPlacement placement);
+  JSONCPP_DEPRECATED("Use setComment(String const&) instead.")
+  void setComment(const char* comment, CommentPlacement placement) {
+    setComment(String(comment, strlen(comment)), placement);
+  }
   /// Comments must be //... or /* ... */
-  void setComment(const char* comment, size_t len, CommentPlacement placement);
+  void setComment(const char* comment, size_t len, CommentPlacement placement) {
+    setComment(String(comment, len), placement);
+  }
   /// Comments must be //... or /* ... */
-  void setComment(const JSONCPP_STRING& comment, CommentPlacement placement);
+  void setComment(String comment, CommentPlacement placement);
   bool hasComment(CommentPlacement placement) const;
   /// Include delimiters and embedded newlines.
-  JSONCPP_STRING getComment(CommentPlacement placement) const;
+  String getComment(CommentPlacement placement) const;
 
-  JSONCPP_STRING toStyledString() const;
+  String toStyledString() const;
 
   const_iterator begin() const;
   const_iterator end() const;
@@ -599,20 +594,20 @@ Json::Value obj_value(Json::objectValue); // {}
   ptrdiff_t getOffsetLimit() const;
 
 private:
+  void setType(ValueType v) {
+    bits_.value_type_ = static_cast<unsigned char>(v);
+  }
+  bool isAllocated() const { return bits_.allocated_; }
+  void setIsAllocated(bool v) { bits_.allocated_ = v; }
+
   void initBasic(ValueType type, bool allocated = false);
+  void dupPayload(const Value& other);
+  void releasePayload();
+  void dupMeta(const Value& other);
 
   Value& resolveReference(const char* key);
   Value& resolveReference(const char* key, const char* end);
 
-  struct CommentInfo {
-    CommentInfo();
-    ~CommentInfo();
-
-    void setComment(const char* text, size_t len);
-
-    char* comment_;
-  };
-
   // struct MemberNamesTransform
   //{
   //   typedef const char *result_type;
@@ -627,13 +622,33 @@ private:
     LargestUInt uint_;
     double real_;
     bool bool_;
-    char* string_;  // actually ptr to unsigned, followed by str, unless !allocated_
+    char* string_; // if allocated_, ptr to { unsigned, char[] }.
     ObjectValues* map_;
   } value_;
-  ValueType type_ : 8;
-  unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
-                               // If not allocated_, string_ must be null-terminated.
-  CommentInfo* comments_;
+
+  struct {
+    // Really a ValueType, but types should agree for bitfield packing.
+    unsigned int value_type_ : 8;
+    // Unless allocated_, string_ must be null-terminated.
+    unsigned int allocated_ : 1;
+  } bits_;
+
+  class Comments {
+  public:
+    Comments() = default;
+    Comments(const Comments& that);
+    Comments(Comments&& that);
+    Comments& operator=(const Comments& that);
+    Comments& operator=(Comments&& that);
+    bool has(CommentPlacement slot) const;
+    String get(CommentPlacement slot) const;
+    void set(CommentPlacement slot, String comment);
+
+  private:
+    using Array = std::array<String, numberOfCommentPlacement>;
+    std::unique_ptr<Array> ptr_;
+  };
+  Comments comments_;
 
   // [start, limit) byte offsets in the source JSON text from which this Value
   // was extracted.
@@ -641,6 +656,36 @@ private:
   ptrdiff_t limit_;
 };
 
+template <> inline bool Value::as<bool>() const { return asBool(); }
+template <> inline bool Value::is<bool>() const { return isBool(); }
+
+template <> inline Int Value::as<Int>() const { return asInt(); }
+template <> inline bool Value::is<Int>() const { return isInt(); }
+
+template <> inline UInt Value::as<UInt>() const { return asUInt(); }
+template <> inline bool Value::is<UInt>() const { return isUInt(); }
+
+#if defined(JSON_HAS_INT64)
+template <> inline Int64 Value::as<Int64>() const { return asInt64(); }
+template <> inline bool Value::is<Int64>() const { return isInt64(); }
+
+template <> inline UInt64 Value::as<UInt64>() const { return asUInt64(); }
+template <> inline bool Value::is<UInt64>() const { return isUInt64(); }
+#endif
+
+template <> inline double Value::as<double>() const { return asDouble(); }
+template <> inline bool Value::is<double>() const { return isDouble(); }
+
+template <> inline String Value::as<String>() const { return asString(); }
+template <> inline bool Value::is<String>() const { return isString(); }
+
+/// These `as` specializations are type conversions, and do not have a
+/// corresponding `is`.
+template <> inline float Value::as<float>() const { return asFloat(); }
+template <> inline const char* Value::as<const char*>() const {
+  return asCString();
+}
+
 /** \brief Experimental and untested: represents an element of the "path" to
  * access a node.
  */
@@ -651,17 +696,13 @@ public:
   PathArgument();
   PathArgument(ArrayIndex index);
   PathArgument(const char* key);
-  PathArgument(const JSONCPP_STRING& key);
+  PathArgument(String key);
 
 private:
-  enum Kind {
-    kindNone = 0,
-    kindIndex,
-    kindKey
-  };
-  JSONCPP_STRING key_;
-  ArrayIndex index_;
-  Kind kind_;
+  enum Kind { kindNone = 0, kindIndex, kindKey };
+  String key_;
+  ArrayIndex index_{};
+  Kind kind_{kindNone};
 };
 
 /** \brief Experimental and untested: represents a "path" to access a node.
@@ -673,12 +714,11 @@ private:
  * - ".name1.name2.name3"
  * - ".[0][1][2].name1[3]"
  * - ".%" => member name is provided as parameter
- * - ".[%]" => index is provied as parameter
+ * - ".[%]" => index is provided as parameter
  */
 class JSON_API Path {
 public:
-  Path(const JSONCPP_STRING& path,
-       const PathArgument& a1 = PathArgument(),
+  Path(const String& path, const PathArgument& a1 = PathArgument(),
        const PathArgument& a2 = PathArgument(),
        const PathArgument& a3 = PathArgument(),
        const PathArgument& a4 = PathArgument(),
@@ -691,15 +731,13 @@ public:
   Value& make(Value& root) const;
 
 private:
-  typedef std::vector<const PathArgument*> InArgs;
-  typedef std::vector<PathArgument> Args;
+  using InArgs = std::vector<const PathArgument*>;
+  using Args = std::vector<PathArgument>;
 
-  void makePath(const JSONCPP_STRING& path, const InArgs& in);
-  void addPathInArg(const JSONCPP_STRING& path,
-                    const InArgs& in,
-                    InArgs::const_iterator& itInArg,
-                    PathArgument::Kind kind);
-  void invalidPath(const JSONCPP_STRING& path, int location);
+  void makePath(const String& path, const InArgs& in);
+  void addPathInArg(const String& path, const InArgs& in,
+                    InArgs::const_iterator& itInArg, PathArgument::Kind kind);
+  static void invalidPath(const String& path, int location);
 
   Args args_;
 };
@@ -709,10 +747,10 @@ private:
  */
 class JSON_API ValueIteratorBase {
 public:
-  typedef std::bidirectional_iterator_tag iterator_category;
-  typedef unsigned int size_t;
-  typedef int difference_type;
-  typedef ValueIteratorBase SelfType;
+  using iterator_category = std::bidirectional_iterator_tag;
+  using size_t = unsigned int;
+  using difference_type = int;
+  using SelfType = ValueIteratorBase;
 
   bool operator==(const SelfType& other) const { return isEqual(other); }
 
@@ -726,17 +764,19 @@ public:
   /// Value.
   Value key() const;
 
-  /// Return the index of the referenced Value, or -1 if it is not an arrayValue.
+  /// Return the index of the referenced Value, or -1 if it is not an
+  /// arrayValue.
   UInt index() const;
 
   /// Return the member name of the referenced Value, or "" if it is not an
   /// objectValue.
   /// \note Avoid `c_str()` on result, as embedded zeroes are possible.
-  JSONCPP_STRING name() const;
+  String name() const;
 
   /// Return the member name of the referenced Value. "" if it is not an
   /// objectValue.
-  /// deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls.
+  /// deprecated This cannot be used for UTF-8 strings, since there can be
+  /// embedded nulls.
   JSONCPP_DEPRECATED("Use `key = name();` instead.")
   char const* memberName() const;
   /// Return the member name of the referenced Value, or NULL if it is not an
@@ -745,7 +785,14 @@ public:
   char const* memberName(char const** end) const;
 
 protected:
-  Value& deref() const;
+  /*! Internal utility functions to assist with implementing
+   *   other iterator functions. The const and non-const versions
+   *   of the "deref" protected methods expose the protected
+   *   current_ member variable in a way that can often be
+   *   optimized away by the compiler.
+   */
+  const Value& deref() const;
+  Value& deref();
 
   void increment();
 
@@ -760,7 +807,7 @@ protected:
 private:
   Value::ObjectValues::iterator current_;
   // Indicates that iterator is for a null value.
-  bool isNull_;
+  bool isNull_{true};
 
 public:
   // For some reason, BORLAND needs these at the end, rather
@@ -776,20 +823,21 @@ class JSON_API ValueConstIterator : public ValueIteratorBase {
   friend class Value;
 
 public:
-  typedef const Value value_type;
-  //typedef unsigned int size_t;
-  //typedef int difference_type;
-  typedef const Value& reference;
-  typedef const Value* pointer;
-  typedef ValueConstIterator SelfType;
+  using value_type = const Value;
+  // typedef unsigned int size_t;
+  // typedef int difference_type;
+  using reference = const Value&;
+  using pointer = const Value*;
+  using SelfType = ValueConstIterator;
 
   ValueConstIterator();
   ValueConstIterator(ValueIterator const& other);
 
 private:
-/*! internal Use by Value to create an iterator.
- */
+  /*! internal Use by Value to create an iterator.
  */
   explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
+
 public:
   SelfType& operator=(const ValueIteratorBase& other);
 
@@ -826,21 +874,22 @@ class JSON_API ValueIterator : public ValueIteratorBase {
   friend class Value;
 
 public:
-  typedef Value value_type;
-  typedef unsigned int size_t;
-  typedef int difference_type;
-  typedef Value& reference;
-  typedef Value* pointer;
-  typedef ValueIterator SelfType;
+  using value_type = Value;
+  using size_t = unsigned int;
+  using difference_type = int;
+  using reference = Value&;
+  using pointer = Value*;
+  using SelfType = ValueIterator;
 
   ValueIterator();
   explicit ValueIterator(const ValueConstIterator& other);
   ValueIterator(const ValueIterator& other);
 
 private:
-/*! internal Use by Value to create an iterator.
- */
+  /*! internal Use by Value to create an iterator.
  */
   explicit ValueIterator(const Value::ObjectValues::iterator& current);
+
 public:
   SelfType& operator=(const SelfType& other);
 
@@ -866,19 +915,18 @@ public:
     return *this;
   }
 
-  reference operator*() const { return deref(); }
-
-  pointer operator->() const { return &deref(); }
+  /*! The return value of non-const iterators can be
+   *  changed, so the these functions are not const
+   *  because the returned references/pointers can be used
+   *  to change state of the base class.
+   */
+  reference operator*() { return deref(); }
+  pointer operator->() { return &deref(); }
 };
 
-} // namespace Json
+inline void swap(Value& a, Value& b) { a.swap(b); }
 
-
-namespace std {
-/// Specialize std::swap() for Json::Value.
-template<>
-inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); }
-}
+} // namespace Json
 
 #if !defined(__SUNPRO_CC)
 #pragma pack(pop)
@@ -888,4 +936,4 @@ inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); }
 #pragma warning(pop)
 #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
 
-#endif // CPPTL_JSON_H_INCLUDED
+#endif // JSON_H_INCLUDED
index d953961..5b9783d 100644 (file)
@@ -1,14 +1,22 @@
-// DO NOT EDIT. This file (and "version") is generated by CMake.
-// Run CMake configure step to update it.
 #ifndef JSON_VERSION_H_INCLUDED
-# define JSON_VERSION_H_INCLUDED
+#define JSON_VERSION_H_INCLUDED
 
-# define JSONCPP_VERSION_STRING "1.8.2"
-# define JSONCPP_VERSION_MAJOR 1
-# define JSONCPP_VERSION_MINOR 8
-# define JSONCPP_VERSION_PATCH 2
-# define JSONCPP_VERSION_QUALIFIER
-# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
+// Note: version must be updated in three places when doing a release. This
+// annoying process ensures that amalgamate, CMake, and meson all report the
+// correct version.
+// 1. /meson.build
+// 2. /include/json/version.h
+// 3. /CMakeLists.txt
+// IMPORTANT: also update the SOVERSION!!
+
+#define JSONCPP_VERSION_STRING "1.9.4"
+#define JSONCPP_VERSION_MAJOR 1
+#define JSONCPP_VERSION_MINOR 9
+#define JSONCPP_VERSION_PATCH 3
+#define JSONCPP_VERSION_QUALIFIER
+#define JSONCPP_VERSION_HEXA                                                   \
+  ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) |             \
+   (JSONCPP_VERSION_PATCH << 8))
 
 #ifdef JSONCPP_USING_SECURE_MEMORY
 #undef JSONCPP_USING_SECURE_MEMORY
index d3ae62b..cc6b78c 100644 (file)
@@ -9,14 +9,13 @@
 #if !defined(JSON_IS_AMALGAMATION)
 #include "value.h"
 #endif // if !defined(JSON_IS_AMALGAMATION)
-#include <iosfwd>
-#include <vector>
-#include <string>
 #include <ostream>
+#include <string>
+#include <vector>
 
 // Disable warning C4251: <data member>: <type> needs to have dll-interface to
 // be used by...
-#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) && defined(_MSC_VER)
 #pragma warning(push)
 #pragma warning(disable : 4251)
 #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
@@ -30,31 +29,31 @@ namespace Json {
 class Value;
 
 /**
-
-Usage:
-\code
-  using namespace Json;
-  void writeToStdout(StreamWriter::Factory const& factory, Value const& value) {
-    std::unique_ptr<StreamWriter> const writer(
-      factory.newStreamWriter());
-    writer->write(value, &std::cout);
-    std::cout << std::endl;  // add lf and flush
-  }
-\endcode
-*/
+ *
+ * Usage:
+ *  \code
+ *  using namespace Json;
+ *  void writeToStdout(StreamWriter::Factory const& factory, Value const& value)
+ * { std::unique_ptr<StreamWriter> const writer( factory.newStreamWriter());
+ *    writer->write(value, &std::cout);
+ *    std::cout << std::endl;  // add lf and flush
+ *  }
+ *  \endcode
+ */
 class JSON_API StreamWriter {
 protected:
-  JSONCPP_OSTREAM* sout_;  // not owned; will not delete
+  OStream* sout_; // not owned; will not delete
 public:
   StreamWriter();
   virtual ~StreamWriter();
   /** Write Value into document as configured in sub-class.
-      Do not take ownership of sout, but maintain a reference during function.
-      \pre sout != NULL
-      \return zero on success (For now, we always return zero, so check the stream instead.)
-      \throw std::exception possibly, depending on configuration
+   *   Do not take ownership of sout, but maintain a reference during function.
+   *   \pre sout != NULL
+   *   \return zero on success (For now, we always return zero, so check the
+   *   stream instead.) \throw std::exception possibly, depending on
+   * configuration
    */
-  virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0;
+  virtual int write(Value const& root, OStream* sout) = 0;
 
   /** \brief A simple abstract factory.
    */
@@ -65,64 +64,69 @@ public:
      * \throw std::exception if something goes wrong (e.g. invalid settings)
      */
     virtual StreamWriter* newStreamWriter() const = 0;
-  };  // Factory
-};  // StreamWriter
+  }; // Factory
+};   // StreamWriter
 
 /** \brief Write into stringstream, then return string, for convenience.
  * A StreamWriter will be created from the factory, used, and then deleted.
  */
-JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, Value const& root);
-
+String JSON_API writeString(StreamWriter::Factory const& factory,
+                            Value const& root);
 
 /** \brief Build a StreamWriter implementation.
 
-Usage:
-\code
-  using namespace Json;
-  Value value = ...;
-  StreamWriterBuilder builder;
-  builder["commentStyle"] = "None";
-  builder["indentation"] = "   ";  // or whatever you like
-  std::unique_ptr<Json::StreamWriter> writer(
-      builder.newStreamWriter());
-  writer->write(value, &std::cout);
-  std::cout << std::endl;  // add lf and flush
-\endcode
+Usage:
+*   \code
+  using namespace Json;
+  Value value = ...;
+  StreamWriterBuilder builder;
+  builder["commentStyle"] = "None";
+  builder["indentation"] = "   ";  // or whatever you like
+  std::unique_ptr<Json::StreamWriter> writer(
+*      builder.newStreamWriter());
+  writer->write(value, &std::cout);
+  std::cout << std::endl;  // add lf and flush
+*   \endcode
 */
 class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
 public:
   // Note: We use a Json::Value so that we can add data-members to this class
   // without a major version bump.
   /** Configuration of this builder.
-    Available settings (case-sensitive):
-    - "commentStyle": "None" or "All"
-    - "indentation":  "<anything>"
-    - "enableYAMLCompatibility": false or true
-      - slightly change the whitespace around colons
-    - "dropNullPlaceholders": false or true
-      - Drop the "null" string from the writer's output for nullValues.
-        Strictly speaking, this is not valid JSON. But when the output is being
-        fed to a browser's Javascript, it makes for smaller output and the
-        browser can handle the output just fine.
-    - "useSpecialFloats": false or true
-      - If true, outputs non-finite floating point values in the following way:
-        NaN values as "NaN", positive infinity as "Infinity", and negative infinity
-        as "-Infinity".
-
-    You can examine 'settings_` yourself
-    to see the defaults. You can also write and read them just like any
-    JSON Value.
-    \sa setDefaults()
-    */
+   *  Available settings (case-sensitive):
+   *  - "commentStyle": "None" or "All"
+   *  - "indentation":  "<anything>".
+   *  - Setting this to an empty string also omits newline characters.
+   *  - "enableYAMLCompatibility": false or true
+   *  - slightly change the whitespace around colons
+   *  - "dropNullPlaceholders": false or true
+   *  - Drop the "null" string from the writer's output for nullValues.
+   *    Strictly speaking, this is not valid JSON. But when the output is being
+   *    fed to a browser's JavaScript, it makes for smaller output and the
+   *    browser can handle the output just fine.
+   *  - "useSpecialFloats": false or true
+   *  - If true, outputs non-finite floating point values in the following way:
+   *    NaN values as "NaN", positive infinity as "Infinity", and negative
+   *  infinity as "-Infinity".
+   *  - "precision": int
+   *  - Number of precision digits for formatting of real values.
+   *  - "precisionType": "significant"(default) or "decimal"
+   *  - Type of precision for formatting of real values.
+
+   *  You can examine 'settings_` yourself
+   *  to see the defaults. You can also write and read them just like any
+   *  JSON Value.
+   *  \sa setDefaults()
+   */
   Json::Value settings_;
 
   StreamWriterBuilder();
-  ~StreamWriterBuilder() JSONCPP_OVERRIDE;
+  ~StreamWriterBuilder() override;
 
   /**
    * \throw std::exception if something goes wrong (e.g. invalid settings)
    */
-  StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE;
+  StreamWriter* newStreamWriter() const override;
 
   /** \return true if 'settings' are legal and consistent;
    *   otherwise, indicate bad settings via 'invalid'.
@@ -130,7 +134,7 @@ public:
   bool validate(Json::Value* invalid) const;
   /** A simple way to update a specific setting.
    */
-  Value& operator[](JSONCPP_STRING key);
+  Value& operator[](const String& key);
 
   /** Called by ctor, but you can use this to reset settings_.
    * \pre 'settings' != NULL (but Json::null is fine)
@@ -147,7 +151,7 @@ class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer {
 public:
   virtual ~Writer();
 
-  virtual JSONCPP_STRING write(const Value& root) = 0;
+  virtual String write(const Value& root) = 0;
 };
 
 /** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
@@ -155,21 +159,25 @@ public:
  *
  * The JSON document is written in a single line. It is not intended for 'human'
  *consumption,
- * but may be usefull to support feature such as RPC where bandwith is limited.
+ * but may be useful to support feature such as RPC where bandwidth is limited.
  * \sa Reader, Value
  * deprecated Use StreamWriterBuilder.
  */
-class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter : public Writer {
-
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4996) // Deriving from deprecated class
+#endif
+class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter
+    : public Writer {
 public:
   FastWriter();
-  ~FastWriter() JSONCPP_OVERRIDE {}
+  ~FastWriter() override = default;
 
   void enableYAMLCompatibility();
 
   /** \brief Drop the "null" string from the writer's output for nullValues.
    * Strictly speaking, this is not valid JSON. But when the output is being
-   * fed to a browser's Javascript, it makes for smaller output and the
+   * fed to a browser's JavaScript, it makes for smaller output and the
    * browser can handle the output just fine.
    */
   void dropNullPlaceholders();
@@ -177,16 +185,19 @@ public:
   void omitEndingLineFeed();
 
 public: // overridden from Writer
-  JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE;
+  String write(const Value& root) override;
 
 private:
   void writeValue(const Value& value);
 
-  JSONCPP_STRING document_;
-  bool yamlCompatiblityEnabled_;
-  bool dropNullPlaceholders_;
-  bool omitEndingLineFeed_;
+  String document_;
+  bool yamlCompatibilityEnabled_{false};
+  bool dropNullPlaceholders_{false};
+  bool omitEndingLineFeed_{false};
 };
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
 
 /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
  *human friendly way.
@@ -212,41 +223,49 @@ private:
  * \sa Reader, Value, Value::setComment()
  * deprecated Use StreamWriterBuilder.
  */
-class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API StyledWriter : public Writer {
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4996) // Deriving from deprecated class
+#endif
+class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
+    StyledWriter : public Writer {
 public:
   StyledWriter();
-  ~StyledWriter() JSONCPP_OVERRIDE {}
+  ~StyledWriter() override = default;
 
 public: // overridden from Writer
   /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
    * \param root Value to serialize.
    * \return String containing the JSON document that represents the root value.
    */
-  JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE;
+  String write(const Value& root) override;
 
 private:
   void writeValue(const Value& value);
   void writeArrayValue(const Value& value);
-  bool isMultineArray(const Value& value);
-  void pushValue(const JSONCPP_STRING& value);
+  bool isMultilineArray(const Value& value);
+  void pushValue(const String& value);
   void writeIndent();
-  void writeWithIndent(const JSONCPP_STRING& value);
+  void writeWithIndent(const String& value);
   void indent();
   void unindent();
   void writeCommentBeforeValue(const Value& root);
   void writeCommentAfterValueOnSameLine(const Value& root);
-  bool hasCommentForValue(const Value& value);
-  static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text);
+  static bool hasCommentForValue(const Value& value);
+  static String normalizeEOL(const String& text);
 
-  typedef std::vector<JSONCPP_STRING> ChildValues;
+  using ChildValues = std::vector<String>;
 
   ChildValues childValues_;
-  JSONCPP_STRING document_;
-  JSONCPP_STRING indentString_;
-  unsigned int rightMargin_;
-  unsigned int indentSize_;
-  bool addChildValues_;
+  String document_;
+  String indentString_;
+  unsigned int rightMargin_{74};
+  unsigned int indentSize_{3};
+  bool addChildValues_{false};
 };
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
 
 /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
  human friendly way,
@@ -273,13 +292,18 @@ private:
  * \sa Reader, Value, Value::setComment()
  * deprecated Use StreamWriterBuilder.
  */
-class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API StyledStreamWriter {
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4996) // Deriving from deprecated class
+#endif
+class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
+    StyledStreamWriter {
 public:
-/**
- * \param indentation Each level will be indented by this amount extra.
- */
-  StyledStreamWriter(JSONCPP_STRING indentation = "\t");
-  ~StyledStreamWriter() {}
+  /**
  * \param indentation Each level will be indented by this amount extra.
  */
+  StyledStreamWriter(String indentation = "\t");
+  ~StyledStreamWriter() = default;
 
 public:
   /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
@@ -288,46 +312,51 @@ public:
    * \note There is no point in deriving from Writer, since write() should not
    * return a value.
    */
-  void write(JSONCPP_OSTREAM& out, const Value& root);
+  void write(OStream& out, const Value& root);
 
 private:
   void writeValue(const Value& value);
   void writeArrayValue(const Value& value);
-  bool isMultineArray(const Value& value);
-  void pushValue(const JSONCPP_STRING& value);
+  bool isMultilineArray(const Value& value);
+  void pushValue(const String& value);
   void writeIndent();
-  void writeWithIndent(const JSONCPP_STRING& value);
+  void writeWithIndent(const String& value);
   void indent();
   void unindent();
   void writeCommentBeforeValue(const Value& root);
   void writeCommentAfterValueOnSameLine(const Value& root);
-  bool hasCommentForValue(const Value& value);
-  static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text);
+  static bool hasCommentForValue(const Value& value);
+  static String normalizeEOL(const String& text);
 
-  typedef std::vector<JSONCPP_STRING> ChildValues;
+  using ChildValues = std::vector<String>;
 
   ChildValues childValues_;
-  JSONCPP_OSTREAM* document_;
-  JSONCPP_STRING indentString_;
-  unsigned int rightMargin_;
-  JSONCPP_STRING indentation_;
+  OStream* document_;
+  String indentString_;
+  unsigned int rightMargin_{74};
+  String indentation_;
   bool addChildValues_ : 1;
   bool indented_ : 1;
 };
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
 
 #if defined(JSON_HAS_INT64)
-JSONCPP_STRING JSON_API valueToString(Int value);
-JSONCPP_STRING JSON_API valueToString(UInt value);
+String JSON_API valueToString(Int value);
+String JSON_API valueToString(UInt value);
 #endif // if defined(JSON_HAS_INT64)
-JSONCPP_STRING JSON_API valueToString(LargestInt value);
-JSONCPP_STRING JSON_API valueToString(LargestUInt value);
-JSONCPP_STRING JSON_API valueToString(double value);
-JSONCPP_STRING JSON_API valueToString(bool value);
-JSONCPP_STRING JSON_API valueToQuotedString(const char* value);
+String JSON_API valueToString(LargestInt value);
+String JSON_API valueToString(LargestUInt value);
+String JSON_API valueToString(
+    double value, unsigned int precision = Value::defaultRealPrecision,
+    PrecisionType precisionType = PrecisionType::significantDigits);
+String JSON_API valueToString(bool value);
+String JSON_API valueToQuotedString(const char* value);
 
 /// \brief Output using the StyledStreamWriter.
 /// \see Json::operator>>()
-JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root);
+JSON_API OStream& operator<<(OStream&, const Value& root);
 
 } // namespace Json
 
index 8291cc6..e6caf40 100644 (file)
@@ -5,69 +5,65 @@
 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
 
 #if !defined(JSON_IS_AMALGAMATION)
+#include "json_tool.h"
 #include <json/assertions.h>
 #include <json/reader.h>
 #include <json/value.h>
-#include "json_tool.h"
 #endif // if !defined(JSON_IS_AMALGAMATION)
-#include <utility>
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <iostream>
 #include <istream>
-#include <sstream>
+#include <limits>
 #include <memory>
 #include <set>
-#include <limits>
+#include <sstream>
+#include <utility>
 
-#if defined(_MSC_VER)
-#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above 
-#define snprintf sprintf_s
-#elif _MSC_VER >= 1900 // VC++ 14.0 and above
-#define snprintf std::snprintf
-#else
-#define snprintf _snprintf
-#endif
-#elif defined(__ANDROID__) || defined(__QNXNTO__)
-#define snprintf snprintf
-#elif __cplusplus >= 201103L
-#if !defined(__MINGW32__) && !defined(__CYGWIN__)
-#define snprintf std::snprintf
-#endif
-#endif
+#include <cstdio>
+#if __cplusplus >= 201103L
 
-#if defined(__QNXNTO__)
+#if !defined(sscanf)
 #define sscanf std::sscanf
 #endif
 
-#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
+#endif //__cplusplus
+
+#if defined(_MSC_VER)
+#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
+#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
+#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
+#endif //_MSC_VER
+
+#if defined(_MSC_VER)
 // Disable warning about strdup being deprecated.
 #pragma warning(disable : 4996)
 #endif
 
-// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit
+// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile
+// time to change the stack limit
 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
 #define JSONCPP_DEPRECATED_STACK_LIMIT 1000
 #endif
 
-static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
+static size_t const stackLimit_g =
+    JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
 
 namespace Json {
 
 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
-typedef std::unique_ptr<CharReader> CharReaderPtr;
+using CharReaderPtr = std::unique_ptr<CharReader>;
 #else
-typedef std::auto_ptr<CharReader>   CharReaderPtr;
+using CharReaderPtr = std::auto_ptr<CharReader>;
 #endif
 
 // Implementation of class Features
 // ////////////////////////////////
 
-Features::Features()
-    : allowComments_(true), strictRoot_(false),
-      allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
+Features::Features() = default;
 
-Features Features::all() { return Features(); }
+Features Features::all() { return {}; }
 
 Features Features::strictMode() {
   Features features;
@@ -82,49 +78,38 @@ Features Features::strictMode() {
 // ////////////////////////////////
 
 bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
-  for (; begin < end; ++begin)
-    if (*begin == '\n' || *begin == '\r')
-      return true;
-  return false;
+  return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
 }
 
 // Class Reader
 // //////////////////////////////////////////////////////////////////
 
-Reader::Reader()
-    : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
-      lastValue_(), commentsBefore_(), features_(Features::all()),
-      collectComments_() {}
+Reader::Reader() : features_(Features::all()) {}
 
-Reader::Reader(const Features& features)
-    : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
-      lastValue_(), commentsBefore_(), features_(features), collectComments_() {
-}
+Reader::Reader(const Features& features) : features_(features) {}
 
-bool
-Reader::parse(const std::string& document, Value& root, bool collectComments) {
+bool Reader::parse(const std::string& document, Value& root,
+                   bool collectComments) {
   document_.assign(document.begin(), document.end());
   const char* begin = document_.c_str();
   const char* end = begin + document_.length();
   return parse(begin, end, root, collectComments);
 }
 
-bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
-  // std::istream_iterator<char> begin(sin);
+bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
+  // std::istream_iterator<char> begin(is);
   // std::istream_iterator<char> end;
   // Those would allow streamed input from a file, if parse() were a
   // template function.
 
-  // Since JSONCPP_STRING is reference-counted, this at least does not
+  // Since String is reference-counted, this at least does not
   // create an extra copy.
-  JSONCPP_STRING doc;
-  std::getline(sin, doc, (char)EOF);
+  String doc;
+  std::getline(is, doc, static_cast<char> EOF);
   return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
 }
 
-bool Reader::parse(const char* beginDoc,
-                   const char* endDoc,
-                   Value& root,
+bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
                    bool collectComments) {
   if (!features_.allowComments_) {
     collectComments = false;
@@ -134,8 +119,8 @@ bool Reader::parse(const char* beginDoc,
   end_ = endDoc;
   collectComments_ = collectComments;
   current_ = begin_;
-  lastValueEnd_ = 0;
-  lastValue_ = 0;
+  lastValueEnd_ = nullptr;
+  lastValue_ = nullptr;
   commentsBefore_.clear();
   errors_.clear();
   while (!nodes_.empty())
@@ -165,9 +150,11 @@ bool Reader::parse(const char* beginDoc,
 
 bool Reader::readValue() {
   // readValue() may call itself only if it calls readObject() or ReadArray().
-  // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue(). 
-  // parse() executes one nodes_.push(), so > instead of >=.
-  if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
+  // These methods execute nodes_.push() just before and nodes_.pop)() just
+  // after calling readValue(). parse() executes one nodes_.push(), so > instead
+  // of >=.
+  if (nodes_.size() > stackLimit_g)
+    throwRuntimeError("Exceeded stackLimit in readValue().");
 
   Token token;
   skipCommentTokens(token);
@@ -193,30 +180,24 @@ bool Reader::readValue() {
   case tokenString:
     successful = decodeString(token);
     break;
-  case tokenTrue:
-    {
+  case tokenTrue: {
     Value v(true);
     currentValue().swapPayload(v);
     currentValue().setOffsetStart(token.start_ - begin_);
     currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenFalse:
-    {
+  } break;
+  case tokenFalse: {
     Value v(false);
     currentValue().swapPayload(v);
     currentValue().setOffsetStart(token.start_ - begin_);
     currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenNull:
-    {
+  } break;
+  case tokenNull: {
     Value v;
     currentValue().swapPayload(v);
     currentValue().setOffsetStart(token.start_ - begin_);
     currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
+  } break;
   case tokenArraySeparator:
   case tokenObjectEnd:
   case tokenArrayEnd:
@@ -322,7 +303,7 @@ bool Reader::readToken(Token& token) {
   if (!ok)
     token.type_ = tokenError;
   token.end_ = current_;
-  return true;
+  return ok;
 }
 
 void Reader::skipSpaces() {
@@ -335,7 +316,7 @@ void Reader::skipSpaces() {
   }
 }
 
-bool Reader::match(Location pattern, int patternLength) {
+bool Reader::match(const Char* pattern, int patternLength) {
   if (end_ - current_ < patternLength)
     return false;
   int index = patternLength;
@@ -369,16 +350,16 @@ bool Reader::readComment() {
   return true;
 }
 
-JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
-  JSONCPP_STRING normalized;
+String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
+  String normalized;
   normalized.reserve(static_cast<size_t>(end - begin));
   Reader::Location current = begin;
   while (current != end) {
     char c = *current++;
     if (c == '\r') {
       if (current != end && *current == '\n')
-         // convert dos EOL
-         ++current;
+        // convert dos EOL
+        ++current;
       // convert Mac EOL
       normalized += '\n';
     } else {
@@ -388,12 +369,12 @@ JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end
   return normalized;
 }
 
-void
-Reader::addComment(Location begin, Location end, CommentPlacement placement) {
+void Reader::addComment(Location begin, Location end,
+                        CommentPlacement placement) {
   assert(collectComments_);
-  const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
+  const String& normalized = normalizeEOL(begin, end);
   if (placement == commentAfterOnSameLine) {
-    assert(lastValue_ != 0);
+    assert(lastValue_ != nullptr);
     lastValue_->setComment(normalized, placement);
   } else {
     commentsBefore_ += normalized;
@@ -426,7 +407,7 @@ bool Reader::readCppStyleComment() {
 }
 
 void Reader::readNumber() {
-  const char *p = current_;
+  Location p = current_;
   char c = '0'; // stopgap for already consumed character
   // integral part
   while (c >= '0' && c <= '9')
@@ -459,12 +440,12 @@ bool Reader::readString() {
   return c == '"';
 }
 
-bool Reader::readObject(Token& tokenStart) {
+bool Reader::readObject(Token& token) {
   Token tokenName;
-  JSONCPP_STRING name;
+  String name;
   Value init(objectValue);
   currentValue().swapPayload(init);
-  currentValue().setOffsetStart(tokenStart.start_ - begin_);
+  currentValue().setOffsetStart(token.start_ - begin_);
   while (readToken(tokenName)) {
     bool initialTokenOk = true;
     while (tokenName.type_ == tokenComment && initialTokenOk)
@@ -481,15 +462,15 @@ bool Reader::readObject(Token& tokenStart) {
       Value numberName;
       if (!decodeNumber(tokenName, numberName))
         return recoverFromError(tokenObjectEnd);
-      name = JSONCPP_STRING(numberName.asCString());
+      name = numberName.asString();
     } else {
       break;
     }
 
     Token colon;
     if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
-      return addErrorAndRecover(
-          "Missing ':' after object member name", colon, tokenObjectEnd);
+      return addErrorAndRecover("Missing ':' after object member name", colon,
+                                tokenObjectEnd);
     }
     Value& value = currentValue()[name];
     nodes_.push(&value);
@@ -502,8 +483,8 @@ bool Reader::readObject(Token& tokenStart) {
     if (!readToken(comma) ||
         (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
          comma.type_ != tokenComment)) {
-      return addErrorAndRecover(
-          "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
+      return addErrorAndRecover("Missing ',' or '}' in object declaration",
+                                comma, tokenObjectEnd);
     }
     bool finalizeTokenOk = true;
     while (comma.type_ == tokenComment && finalizeTokenOk)
@@ -511,14 +492,14 @@ bool Reader::readObject(Token& tokenStart) {
     if (comma.type_ == tokenObjectEnd)
       return true;
   }
-  return addErrorAndRecover(
-      "Missing '}' or object member name", tokenName, tokenObjectEnd);
+  return addErrorAndRecover("Missing '}' or object member name", tokenName,
+                            tokenObjectEnd);
 }
 
-bool Reader::readArray(Token& tokenStart) {
+bool Reader::readArray(Token& token) {
   Value init(arrayValue);
   currentValue().swapPayload(init);
-  currentValue().setOffsetStart(tokenStart.start_ - begin_);
+  currentValue().setOffsetStart(token.start_ - begin_);
   skipSpaces();
   if (current_ != end_ && *current_ == ']') // empty array
   {
@@ -535,19 +516,19 @@ bool Reader::readArray(Token& tokenStart) {
     if (!ok) // error already set
       return recoverFromError(tokenArrayEnd);
 
-    Token token;
+    Token currentToken;
     // Accept Comment after last item in the array.
-    ok = readToken(token);
-    while (token.type_ == tokenComment && ok) {
-      ok = readToken(token);
+    ok = readToken(currentToken);
+    while (currentToken.type_ == tokenComment && ok) {
+      ok = readToken(currentToken);
     }
-    bool badTokenType =
-        (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
+    bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
+                         currentToken.type_ != tokenArrayEnd);
     if (!ok || badTokenType) {
-      return addErrorAndRecover(
-          "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
+      return addErrorAndRecover("Missing ',' or ']' in array declaration",
+                                currentToken, tokenArrayEnd);
     }
-    if (token.type_ == tokenArrayEnd)
+    if (currentToken.type_ == tokenArrayEnd)
       break;
   }
   return true;
@@ -571,7 +552,8 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
   bool isNegative = *current == '-';
   if (isNegative)
     ++current;
-  // TODO: Help the compiler do the div and mod at compile time or get rid of them.
+  // TODO: Help the compiler do the div and mod at compile time or get rid of
+  // them.
   Value::LargestUInt maxIntegerValue =
       isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
                  : Value::maxLargestUInt;
@@ -581,7 +563,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
     Char c = *current++;
     if (c < '0' || c > '9')
       return decodeDouble(token, decoded);
-    Value::UInt digit(static_cast<Value::UInt>(c - '0'));
+    auto digit(static_cast<Value::UInt>(c - '0'));
     if (value >= threshold) {
       // We've hit or exceeded the max value divided by 10 (rounded down). If
       // a) we've only just touched the limit, b) this is the last digit, and
@@ -617,18 +599,17 @@ bool Reader::decodeDouble(Token& token) {
 
 bool Reader::decodeDouble(Token& token, Value& decoded) {
   double value = 0;
-  JSONCPP_STRING buffer(token.start_, token.end_);
-  JSONCPP_ISTRINGSTREAM is(buffer);
+  String buffer(token.start_, token.end_);
+  IStringStream is(buffer);
   if (!(is >> value))
-    return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
-                        "' is not a number.",
-                    token);
+    return addError(
+        "'" + String(token.start_, token.end_) + "' is not a number.", token);
   decoded = value;
   return true;
 }
 
 bool Reader::decodeString(Token& token) {
-  JSONCPP_STRING decoded_string;
+  String decoded_string;
   if (!decodeString(token, decoded_string))
     return false;
   Value decoded(decoded_string);
@@ -638,7 +619,7 @@ bool Reader::decodeString(Token& token) {
   return true;
 }
 
-bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) {
+bool Reader::decodeString(Token& token, String& decoded) {
   decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
   Location current = token.start_ + 1; // skip '"'
   Location end = token.end_ - 1;       // do not include '"'
@@ -646,7 +627,7 @@ bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) {
     Char c = *current++;
     if (c == '"')
       break;
-    else if (c == '\\') {
+    if (c == '\\') {
       if (current == end)
         return addError("Empty escape sequence in string", token, current);
       Char escape = *current++;
@@ -691,10 +672,8 @@ bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) {
   return true;
 }
 
-bool Reader::decodeUnicodeCodePoint(Token& token,
-                                    Location& current,
-                                    Location end,
-                                    unsigned int& unicode) {
+bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,
+                                    Location end, unsigned int& unicode) {
 
   if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
     return false;
@@ -703,10 +682,9 @@ bool Reader::decodeUnicodeCodePoint(Token& token,
     if (end - current < 6)
       return addError(
           "additional six characters expected to parse unicode surrogate pair.",
-          token,
-          current);
-    unsigned int surrogatePair;
+          token, current);
     if (*(current++) == '\\' && *(current++) == 'u') {
+      unsigned int surrogatePair;
       if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
         unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
       } else
@@ -714,20 +692,17 @@ bool Reader::decodeUnicodeCodePoint(Token& token,
     } else
       return addError("expecting another \\u token to begin the second half of "
                       "a unicode surrogate pair",
-                      token,
-                      current);
+                      token, current);
   }
   return true;
 }
 
-bool Reader::decodeUnicodeEscapeSequence(Token& token,
-                                         Location& current,
+bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,
                                          Location end,
                                          unsigned int& ret_unicode) {
   if (end - current < 4)
     return addError(
-        "Bad unicode escape sequence in string: four digits expected.",
-        token,
+        "Bad unicode escape sequence in string: four digits expected.", token,
         current);
   int unicode = 0;
   for (int index = 0; index < 4; ++index) {
@@ -742,15 +717,13 @@ bool Reader::decodeUnicodeEscapeSequence(Token& token,
     else
       return addError(
           "Bad unicode escape sequence in string: hexadecimal digit expected.",
-          token,
-          current);
+          token, current);
   }
   ret_unicode = static_cast<unsigned int>(unicode);
   return true;
 }
 
-bool
-Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
+bool Reader::addError(const String& message, Token& token, Location extra) {
   ErrorInfo info;
   info.token_ = token;
   info.message_ = message;
@@ -772,8 +745,7 @@ bool Reader::recoverFromError(TokenType skipUntilToken) {
   return false;
 }
 
-bool Reader::addErrorAndRecover(const JSONCPP_STRING& message,
-                                Token& token,
+bool Reader::addErrorAndRecover(const String& message, Token& token,
                                 TokenType skipUntilToken) {
   addError(message, token);
   return recoverFromError(skipUntilToken);
@@ -787,8 +759,7 @@ Reader::Char Reader::getNextChar() {
   return *current_++;
 }
 
-void Reader::getLocationLineAndColumn(Location location,
-                                      int& line,
+void Reader::getLocationLineAndColumn(Location location, int& line,
                                       int& column) const {
   Location current = begin_;
   Location lastLineStart = current;
@@ -810,25 +781,22 @@ void Reader::getLocationLineAndColumn(Location location,
   ++line;
 }
 
-JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const {
+String Reader::getLocationLineAndColumn(Location location) const {
   int line, column;
   getLocationLineAndColumn(location, line, column);
   char buffer[18 + 16 + 16 + 1];
-  snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+  jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
   return buffer;
 }
 
 // Deprecated. Preserved for backward compatibility
-JSONCPP_STRING Reader::getFormatedErrorMessages() const {
+String Reader::getFormatedErrorMessages() const {
   return getFormattedErrorMessages();
 }
 
-JSONCPP_STRING Reader::getFormattedErrorMessages() const {
-  JSONCPP_STRING formattedMessage;
-  for (Errors::const_iterator itError = errors_.begin();
-       itError != errors_.end();
-       ++itError) {
-    const ErrorInfo& error = *itError;
+String Reader::getFormattedErrorMessages() const {
+  String formattedMessage;
+  for (const auto& error : errors_) {
     formattedMessage +=
         "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
     formattedMessage += "  " + error.message_ + "\n";
@@ -841,10 +809,7 @@ JSONCPP_STRING Reader::getFormattedErrorMessages() const {
 
 std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
   std::vector<Reader::StructuredError> allErrors;
-  for (Errors::const_iterator itError = errors_.begin();
-       itError != errors_.end();
-       ++itError) {
-    const ErrorInfo& error = *itError;
+  for (const auto& error : errors_) {
     Reader::StructuredError structured;
     structured.offset_start = error.token_.start_ - begin_;
     structured.offset_limit = error.token_.end_ - begin_;
@@ -854,28 +819,27 @@ std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
   return allErrors;
 }
 
-bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) {
+bool Reader::pushError(const Value& value, const String& message) {
   ptrdiff_t const length = end_ - begin_;
-  if(value.getOffsetStart() > length
-    || value.getOffsetLimit() > length)
+  if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
     return false;
   Token token;
   token.type_ = tokenError;
   token.start_ = begin_ + value.getOffsetStart();
-  token.end_ = end_ + value.getOffsetLimit();
+  token.end_ = begin_ + value.getOffsetLimit();
   ErrorInfo info;
   info.token_ = token;
   info.message_ = message;
-  info.extra_ = 0;
+  info.extra_ = nullptr;
   errors_.push_back(info);
   return true;
 }
 
-bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
+bool Reader::pushError(const Value& value, const String& message,
+                       const Value& extra) {
   ptrdiff_t const length = end_ - begin_;
-  if(value.getOffsetStart() > length
-    || value.getOffsetLimit() > length
-    || extra.getOffsetLimit() > length)
+  if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
+      extra.getOffsetLimit() > length)
     return false;
   Token token;
   token.type_ = tokenError;
@@ -889,15 +853,15 @@ bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const
   return true;
 }
 
-bool Reader::good() const {
-  return !errors_.size();
-}
+bool Reader::good() const { return errors_.empty(); }
 
-// exact copy of Features
+// Originally copied from the Features class (now deprecated), used internally
+// for features implementation.
 class OurFeatures {
 public:
   static OurFeatures all();
   bool allowComments_;
+  bool allowTrailingCommas_;
   bool strictRoot_;
   bool allowDroppedNullPlaceholders_;
   bool allowNumericKeys_;
@@ -905,42 +869,36 @@ public:
   bool failIfExtra_;
   bool rejectDupKeys_;
   bool allowSpecialFloats_;
-  int stackLimit_;
-};  // OurFeatures
-
-// exact copy of Implementation of class Features
-// ////////////////////////////////
+  bool skipBom_;
+  size_t stackLimit_;
+}; // OurFeatures
 
-OurFeatures OurFeatures::all() { return OurFeatures(); }
+OurFeatures OurFeatures::all() { return {}; }
 
 // Implementation of class Reader
 // ////////////////////////////////
 
-// exact copy of Reader, renamed to OurReader
+// Originally copied from the Reader class (now deprecated), used internally
+// for implementing JSON reading.
 class OurReader {
 public:
-  typedef char Char;
-  typedef const Char* Location;
+  using Char = char;
+  using Location = const Char*;
   struct StructuredError {
     ptrdiff_t offset_start;
     ptrdiff_t offset_limit;
-    JSONCPP_STRING message;
+    String message;
   };
 
-  OurReader(OurFeatures const& features);
-  bool parse(const char* beginDoc,
-             const char* endDoc,
-             Value& root,
+  explicit OurReader(OurFeatures const& features);
+  bool parse(const char* beginDoc, const char* endDoc, Value& root,
              bool collectComments = true);
-  JSONCPP_STRING getFormattedErrorMessages() const;
+  String getFormattedErrorMessages() const;
   std::vector<StructuredError> getStructuredErrors() const;
-  bool pushError(const Value& value, const JSONCPP_STRING& message);
-  bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra);
-  bool good() const;
 
 private:
-  OurReader(OurReader const&);  // no impl
-  void operator=(OurReader const&);  // no impl
+  OurReader(OurReader const&);      // no impl
+  void operator=(OurReader const&); // no impl
 
   enum TokenType {
     tokenEndOfStream = 0,
@@ -972,17 +930,18 @@ private:
   class ErrorInfo {
   public:
     Token token_;
-    JSONCPP_STRING message_;
+    String message_;
     Location extra_;
   };
 
-  typedef std::deque<ErrorInfo> Errors;
+  using Errors = std::deque<ErrorInfo>;
 
   bool readToken(Token& token);
   void skipSpaces();
-  bool match(Location pattern, int patternLength);
+  void skipBom(bool skipBom);
+  bool match(const Char* pattern, int patternLength);
   bool readComment();
-  bool readCStyleComment();
+  bool readCStyleComment(bool* containsNewLineResult);
   bool readCppStyleComment();
   bool readString();
   bool readStringSingleQuote();
@@ -993,68 +952,57 @@ private:
   bool decodeNumber(Token& token);
   bool decodeNumber(Token& token, Value& decoded);
   bool decodeString(Token& token);
-  bool decodeString(Token& token, JSONCPP_STRING& decoded);
+  bool decodeString(Token& token, String& decoded);
   bool decodeDouble(Token& token);
   bool decodeDouble(Token& token, Value& decoded);
-  bool decodeUnicodeCodePoint(Token& token,
-                              Location& current,
-                              Location end,
+  bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
                               unsigned int& unicode);
-  bool decodeUnicodeEscapeSequence(Token& token,
-                                   Location& current,
-                                   Location end,
-                                   unsigned int& unicode);
-  bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0);
+  bool decodeUnicodeEscapeSequence(Token& token, Location& current,
+                                   Location end, unsigned int& unicode);
+  bool addError(const String& message, Token& token, Location extra = nullptr);
   bool recoverFromError(TokenType skipUntilToken);
-  bool addErrorAndRecover(const JSONCPP_STRING& message,
-                          Token& token,
+  bool addErrorAndRecover(const String& message, Token& token,
                           TokenType skipUntilToken);
   void skipUntilSpace();
   Value& currentValue();
   Char getNextChar();
-  void
-  getLocationLineAndColumn(Location location, int& line, int& column) const;
-  JSONCPP_STRING getLocationLineAndColumn(Location location) const;
+  void getLocationLineAndColumn(Location location, int& line,
+                                int& column) const;
+  String getLocationLineAndColumn(Location location) const;
   void addComment(Location begin, Location end, CommentPlacement placement);
   void skipCommentTokens(Token& token);
 
-  static JSONCPP_STRING normalizeEOL(Location begin, Location end);
+  static String normalizeEOL(Location begin, Location end);
   static bool containsNewLine(Location begin, Location end);
 
-  typedef std::stack<Value*> Nodes;
-  Nodes nodes_;
-  Errors errors_;
-  JSONCPP_STRING document_;
-  Location begin_;
-  Location end_;
-  Location current_;
-  Location lastValueEnd_;
-  Value* lastValue_;
-  JSONCPP_STRING commentsBefore_;
+  using Nodes = std::stack<Value*>;
+
+  Nodes nodes_{};
+  Errors errors_{};
+  String document_{};
+  Location begin_ = nullptr;
+  Location end_ = nullptr;
+  Location current_ = nullptr;
+  Location lastValueEnd_ = nullptr;
+  Value* lastValue_ = nullptr;
+  bool lastValueHasAComment_ = false;
+  String commentsBefore_{};
 
   OurFeatures const features_;
-  bool collectComments_;
-};  // OurReader
+  bool collectComments_ = false;
+}; // OurReader
 
 // complete copy of Read impl, for OurReader
 
-bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location end) {
-  for (; begin < end; ++begin)
-    if (*begin == '\n' || *begin == '\r')
-      return true;
-  return false;
+bool OurReader::containsNewLine(OurReader::Location begin,
+                                OurReader::Location end) {
+  return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
 }
 
-OurReader::OurReader(OurFeatures const& features)
-    : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
-      lastValue_(), commentsBefore_(),
-      features_(features), collectComments_() {
-}
+OurReader::OurReader(OurFeatures const& features) : features_(features) {}
 
-bool OurReader::parse(const char* beginDoc,
-                   const char* endDoc,
-                   Value& root,
-                   bool collectComments) {
+bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
+                      bool collectComments) {
   if (!features_.allowComments_) {
     collectComments = false;
   }
@@ -1063,22 +1011,23 @@ bool OurReader::parse(const char* beginDoc,
   end_ = endDoc;
   collectComments_ = collectComments;
   current_ = begin_;
-  lastValueEnd_ = 0;
-  lastValue_ = 0;
+  lastValueEnd_ = nullptr;
+  lastValue_ = nullptr;
   commentsBefore_.clear();
   errors_.clear();
   while (!nodes_.empty())
     nodes_.pop();
   nodes_.push(&root);
 
+  // skip byte order mark if it exists at the beginning of the UTF-8 text.
+  skipBom(features_.skipBom_);
   bool successful = readValue();
+  nodes_.pop();
   Token token;
   skipCommentTokens(token);
-  if (features_.failIfExtra_) {
-    if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) {
-      addError("Extra non-whitespace after JSON value.", token);
-      return false;
-    }
+  if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
+    addError("Extra non-whitespace after JSON value.", token);
+    return false;
   }
   if (collectComments_ && !commentsBefore_.empty())
     root.setComment(commentsBefore_, commentAfter);
@@ -1100,7 +1049,8 @@ bool OurReader::parse(const char* beginDoc,
 
 bool OurReader::readValue() {
   //  To preserve the old behaviour we cast size_t to int.
-  if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
+  if (nodes_.size() > features_.stackLimit_)
+    throwRuntimeError("Exceeded stackLimit in readValue().");
   Token token;
   skipCommentTokens(token);
   bool successful = true;
@@ -1125,54 +1075,42 @@ bool OurReader::readValue() {
   case tokenString:
     successful = decodeString(token);
     break;
-  case tokenTrue:
-    {
+  case tokenTrue: {
     Value v(true);
     currentValue().swapPayload(v);
     currentValue().setOffsetStart(token.start_ - begin_);
     currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenFalse:
-    {
+  } break;
+  case tokenFalse: {
     Value v(false);
     currentValue().swapPayload(v);
     currentValue().setOffsetStart(token.start_ - begin_);
     currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenNull:
-    {
+  } break;
+  case tokenNull: {
     Value v;
     currentValue().swapPayload(v);
     currentValue().setOffsetStart(token.start_ - begin_);
     currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenNaN:
-    {
+  } break;
+  case tokenNaN: {
     Value v(std::numeric_limits<double>::quiet_NaN());
     currentValue().swapPayload(v);
     currentValue().setOffsetStart(token.start_ - begin_);
     currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenPosInf:
-    {
+  } break;
+  case tokenPosInf: {
     Value v(std::numeric_limits<double>::infinity());
     currentValue().swapPayload(v);
     currentValue().setOffsetStart(token.start_ - begin_);
     currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenNegInf:
-    {
+  } break;
+  case tokenNegInf: {
     Value v(-std::numeric_limits<double>::infinity());
     currentValue().swapPayload(v);
     currentValue().setOffsetStart(token.start_ - begin_);
     currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
+  } break;
   case tokenArraySeparator:
   case tokenObjectEnd:
   case tokenArrayEnd:
@@ -1194,6 +1132,7 @@ bool OurReader::readValue() {
 
   if (collectComments_) {
     lastValueEnd_ = current_;
+    lastValueHasAComment_ = false;
     lastValue_ = &currentValue();
   }
 
@@ -1234,10 +1173,13 @@ bool OurReader::readToken(Token& token) {
     break;
   case '\'':
     if (features_.allowSingleQuotes_) {
-    token.type_ = tokenString;
-    ok = readStringSingleQuote();
+      token.type_ = tokenString;
+      ok = readStringSingleQuote();
+    } else {
+      // If we don't allow single quotes, this is a failure case.
+      ok = false;
+    }
     break;
-    } // else continue
   case '/':
     token.type_ = tokenComment;
     ok = readComment();
@@ -1263,6 +1205,14 @@ bool OurReader::readToken(Token& token) {
       ok = features_.allowSpecialFloats_ && match("nfinity", 7);
     }
     break;
+  case '+':
+    if (readNumber(true)) {
+      token.type_ = tokenNumber;
+    } else {
+      token.type_ = tokenPosInf;
+      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
+    }
+    break;
   case 't':
     token.type_ = tokenTrue;
     ok = match("rue", 3);
@@ -1307,7 +1257,7 @@ bool OurReader::readToken(Token& token) {
   if (!ok)
     token.type_ = tokenError;
   token.end_ = current_;
-  return true;
+  return ok;
 }
 
 void OurReader::skipSpaces() {
@@ -1320,7 +1270,17 @@ void OurReader::skipSpaces() {
   }
 }
 
-bool OurReader::match(Location pattern, int patternLength) {
+void OurReader::skipBom(bool skipBom) {
+  // The default behavior is to skip BOM.
+  if (skipBom) {
+    if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {
+      begin_ += 3;
+      current_ = begin_;
+    }
+  }
+}
+
+bool OurReader::match(const Char* pattern, int patternLength) {
   if (end_ - current_ < patternLength)
     return false;
   int index = patternLength;
@@ -1332,21 +1292,32 @@ bool OurReader::match(Location pattern, int patternLength) {
 }
 
 bool OurReader::readComment() {
-  Location commentBegin = current_ - 1;
-  Char c = getNextChar();
+  const Location commentBegin = current_ - 1;
+  const Char c = getNextChar();
   bool successful = false;
-  if (c == '*')
-    successful = readCStyleComment();
-  else if (c == '/')
+  bool cStyleWithEmbeddedNewline = false;
+
+  const bool isCStyleComment = (c == '*');
+  const bool isCppStyleComment = (c == '/');
+  if (isCStyleComment) {
+    successful = readCStyleComment(&cStyleWithEmbeddedNewline);
+  } else if (isCppStyleComment) {
     successful = readCppStyleComment();
+  }
+
   if (!successful)
     return false;
 
   if (collectComments_) {
     CommentPlacement placement = commentBefore;
-    if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
-      if (c != '*' || !containsNewLine(commentBegin, current_))
-        placement = commentAfterOnSameLine;
+
+    if (!lastValueHasAComment_) {
+      if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
+        if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
+          placement = commentAfterOnSameLine;
+          lastValueHasAComment_ = true;
+        }
+      }
     }
 
     addComment(commentBegin, current_, placement);
@@ -1354,16 +1325,17 @@ bool OurReader::readComment() {
   return true;
 }
 
-JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Location end) {
-  JSONCPP_STRING normalized;
+String OurReader::normalizeEOL(OurReader::Location begin,
+                               OurReader::Location end) {
+  String normalized;
   normalized.reserve(static_cast<size_t>(end - begin));
   OurReader::Location current = begin;
   while (current != end) {
     char c = *current++;
     if (c == '\r') {
       if (current != end && *current == '\n')
-         // convert dos EOL
-         ++current;
+        // convert dos EOL
+        ++current;
       // convert Mac EOL
       normalized += '\n';
     } else {
@@ -1373,24 +1345,29 @@ JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Loc
   return normalized;
 }
 
-void
-OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
+void OurReader::addComment(Location begin, Location end,
+                           CommentPlacement placement) {
   assert(collectComments_);
-  const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
+  const String& normalized = normalizeEOL(begin, end);
   if (placement == commentAfterOnSameLine) {
-    assert(lastValue_ != 0);
+    assert(lastValue_ != nullptr);
     lastValue_->setComment(normalized, placement);
   } else {
     commentsBefore_ += normalized;
   }
 }
 
-bool OurReader::readCStyleComment() {
+bool OurReader::readCStyleComment(bool* containsNewLineResult) {
+  *containsNewLineResult = false;
+
   while ((current_ + 1) < end_) {
     Char c = getNextChar();
     if (c == '*' && *current_ == '/')
       break;
+    if (c == '\n')
+      *containsNewLineResult = true;
   }
+
   return getNextChar() == '/';
 }
 
@@ -1411,7 +1388,7 @@ bool OurReader::readCppStyleComment() {
 }
 
 bool OurReader::readNumber(bool checkInf) {
-  const char *p = current_;
+  Location p = current_;
   if (checkInf && p != end_ && *p == 'I') {
     current_ = ++p;
     return false;
@@ -1448,7 +1425,6 @@ bool OurReader::readString() {
   return c == '"';
 }
 
-
 bool OurReader::readStringSingleQuote() {
   Char c = 0;
   while (current_ != end_) {
@@ -1461,19 +1437,21 @@ bool OurReader::readStringSingleQuote() {
   return c == '\'';
 }
 
-bool OurReader::readObject(Token& tokenStart) {
+bool OurReader::readObject(Token& token) {
   Token tokenName;
-  JSONCPP_STRING name;
+  String name;
   Value init(objectValue);
   currentValue().swapPayload(init);
-  currentValue().setOffsetStart(tokenStart.start_ - begin_);
+  currentValue().setOffsetStart(token.start_ - begin_);
   while (readToken(tokenName)) {
     bool initialTokenOk = true;
     while (tokenName.type_ == tokenComment && initialTokenOk)
       initialTokenOk = readToken(tokenName);
     if (!initialTokenOk)
       break;
-    if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
+    if (tokenName.type_ == tokenObjectEnd &&
+        (name.empty() ||
+         features_.allowTrailingCommas_)) // empty object or trailing comma
       return true;
     name.clear();
     if (tokenName.type_ == tokenString) {
@@ -1487,17 +1465,17 @@ bool OurReader::readObject(Token& tokenStart) {
     } else {
       break;
     }
+    if (name.length() >= (1U << 30))
+      throwRuntimeError("keylength >= 2^30");
+    if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
+      String msg = "Duplicate key: '" + name + "'";
+      return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
+    }
 
     Token colon;
     if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
-      return addErrorAndRecover(
-          "Missing ':' after object member name", colon, tokenObjectEnd);
-    }
-    if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
-    if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
-      JSONCPP_STRING msg = "Duplicate key: '" + name + "'";
-      return addErrorAndRecover(
-          msg, tokenName, tokenObjectEnd);
+      return addErrorAndRecover("Missing ':' after object member name", colon,
+                                tokenObjectEnd);
     }
     Value& value = currentValue()[name];
     nodes_.push(&value);
@@ -1510,8 +1488,8 @@ bool OurReader::readObject(Token& tokenStart) {
     if (!readToken(comma) ||
         (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
          comma.type_ != tokenComment)) {
-      return addErrorAndRecover(
-          "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
+      return addErrorAndRecover("Missing ',' or '}' in object declaration",
+                                comma, tokenObjectEnd);
     }
     bool finalizeTokenOk = true;
     while (comma.type_ == tokenComment && finalizeTokenOk)
@@ -1519,23 +1497,27 @@ bool OurReader::readObject(Token& tokenStart) {
     if (comma.type_ == tokenObjectEnd)
       return true;
   }
-  return addErrorAndRecover(
-      "Missing '}' or object member name", tokenName, tokenObjectEnd);
+  return addErrorAndRecover("Missing '}' or object member name", tokenName,
+                            tokenObjectEnd);
 }
 
-bool OurReader::readArray(Token& tokenStart) {
+bool OurReader::readArray(Token& token) {
   Value init(arrayValue);
   currentValue().swapPayload(init);
-  currentValue().setOffsetStart(tokenStart.start_ - begin_);
-  skipSpaces();
-  if (current_ != end_ && *current_ == ']') // empty array
-  {
-    Token endArray;
-    readToken(endArray);
-    return true;
-  }
+  currentValue().setOffsetStart(token.start_ - begin_);
   int index = 0;
   for (;;) {
+    skipSpaces();
+    if (current_ != end_ && *current_ == ']' &&
+        (index == 0 ||
+         (features_.allowTrailingCommas_ &&
+          !features_.allowDroppedNullPlaceholders_))) // empty array or trailing
+                                                      // comma
+    {
+      Token endArray;
+      readToken(endArray);
+      return true;
+    }
     Value& value = currentValue()[index++];
     nodes_.push(&value);
     bool ok = readValue();
@@ -1543,19 +1525,19 @@ bool OurReader::readArray(Token& tokenStart) {
     if (!ok) // error already set
       return recoverFromError(tokenArrayEnd);
 
-    Token token;
+    Token currentToken;
     // Accept Comment after last item in the array.
-    ok = readToken(token);
-    while (token.type_ == tokenComment && ok) {
-      ok = readToken(token);
+    ok = readToken(currentToken);
+    while (currentToken.type_ == tokenComment && ok) {
+      ok = readToken(currentToken);
     }
-    bool badTokenType =
-        (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
+    bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
+                         currentToken.type_ != tokenArrayEnd);
     if (!ok || badTokenType) {
-      return addErrorAndRecover(
-          "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
+      return addErrorAndRecover("Missing ',' or ']' in array declaration",
+                                currentToken, tokenArrayEnd);
     }
-    if (token.type_ == tokenArrayEnd)
+    if (currentToken.type_ == tokenArrayEnd)
       break;
   }
   return true;
@@ -1576,38 +1558,78 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
   // larger than the maximum supported value of an integer then
   // we decode the number as a double.
   Location current = token.start_;
-  bool isNegative = *current == '-';
-  if (isNegative)
+  const bool isNegative = *current == '-';
+  if (isNegative) {
     ++current;
-  // TODO: Help the compiler do the div and mod at compile time or get rid of them.
-  Value::LargestUInt maxIntegerValue =
-      isNegative ? Value::LargestUInt(Value::minLargestInt)
-                 : Value::maxLargestUInt;
-  Value::LargestUInt threshold = maxIntegerValue / 10;
+  }
+
+  // We assume we can represent the largest and smallest integer types as
+  // unsigned integers with separate sign. This is only true if they can fit
+  // into an unsigned integer.
+  static_assert(Value::maxLargestInt <= Value::maxLargestUInt,
+                "Int must be smaller than UInt");
+
+  // We need to convert minLargestInt into a positive number. The easiest way
+  // to do this conversion is to assume our "threshold" value of minLargestInt
+  // divided by 10 can fit in maxLargestInt when absolute valued. This should
+  // be a safe assumption.
+  static_assert(Value::minLargestInt <= -Value::maxLargestInt,
+                "The absolute value of minLargestInt must be greater than or "
+                "equal to maxLargestInt");
+  static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt,
+                "The absolute value of minLargestInt must be only 1 magnitude "
+                "larger than maxLargest Int");
+
+  static constexpr Value::LargestUInt positive_threshold =
+      Value::maxLargestUInt / 10;
+  static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10;
+
+  // For the negative values, we have to be more careful. Since typically
+  // -Value::minLargestInt will cause an overflow, we first divide by 10 and
+  // then take the inverse. This assumes that minLargestInt is only a single
+  // power of 10 different in magnitude, which we check above. For the last
+  // digit, we take the modulus before negating for the same reason.
+  static constexpr auto negative_threshold =
+      Value::LargestUInt(-(Value::minLargestInt / 10));
+  static constexpr auto negative_last_digit =
+      Value::UInt(-(Value::minLargestInt % 10));
+
+  const Value::LargestUInt threshold =
+      isNegative ? negative_threshold : positive_threshold;
+  const Value::UInt max_last_digit =
+      isNegative ? negative_last_digit : positive_last_digit;
+
   Value::LargestUInt value = 0;
   while (current < token.end_) {
     Char c = *current++;
     if (c < '0' || c > '9')
       return decodeDouble(token, decoded);
-    Value::UInt digit(static_cast<Value::UInt>(c - '0'));
+
+    const auto digit(static_cast<Value::UInt>(c - '0'));
     if (value >= threshold) {
       // We've hit or exceeded the max value divided by 10 (rounded down). If
-      // a) we've only just touched the limit, b) this is the last digit, and
+      // a) we've only just touched the limit, meaing value == threshold,
+      // b) this is the last digit, or
       // c) it's small enough to fit in that rounding delta, we're okay.
       // Otherwise treat this number as a double to avoid overflow.
       if (value > threshold || current != token.end_ ||
-          digit > maxIntegerValue % 10) {
+          digit > max_last_digit) {
         return decodeDouble(token, decoded);
       }
     }
     value = value * 10 + digit;
   }
-  if (isNegative)
-    decoded = -Value::LargestInt(value);
-  else if (value <= Value::LargestUInt(Value::maxInt))
+
+  if (isNegative) {
+    // We use the same magnitude assumption here, just in case.
+    const auto last_digit = static_cast<Value::UInt>(value % 10);
+    decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
+  } else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
     decoded = Value::LargestInt(value);
-  else
+  } else {
     decoded = value;
+  }
+
   return true;
 }
 
@@ -1623,44 +1645,18 @@ bool OurReader::decodeDouble(Token& token) {
 
 bool OurReader::decodeDouble(Token& token, Value& decoded) {
   double value = 0;
-  const int bufferSize = 32;
-  int count;
-  ptrdiff_t const length = token.end_ - token.start_;
-
-  // Sanity check to avoid buffer overflow exploits.
-  if (length < 0) {
-    return addError("Unable to parse token length", token);
-  }
-  size_t const ulength = static_cast<size_t>(length);
-
-  // Avoid using a string constant for the format control string given to
-  // sscanf, as this can cause hard to debug crashes on OS X. See here for more
-  // info:
-  //
-  //     http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
-  char format[] = "%lf";
-
-  if (length <= bufferSize) {
-    Char buffer[bufferSize + 1];
-    memcpy(buffer, token.start_, ulength);
-    buffer[length] = 0;
-    fixNumericLocaleInput(buffer, buffer + length);
-    count = sscanf(buffer, format, &value);
-  } else {
-    JSONCPP_STRING buffer(token.start_, token.end_);
-    count = sscanf(buffer.c_str(), format, &value);
+  const String buffer(token.start_, token.end_);
+  IStringStream is(buffer);
+  if (!(is >> value)) {
+    return addError(
+        "'" + String(token.start_, token.end_) + "' is not a number.", token);
   }
-
-  if (count != 1)
-    return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
-                        "' is not a number.",
-                    token);
   decoded = value;
   return true;
 }
 
 bool OurReader::decodeString(Token& token) {
-  JSONCPP_STRING decoded_string;
+  String decoded_string;
   if (!decodeString(token, decoded_string))
     return false;
   Value decoded(decoded_string);
@@ -1670,7 +1666,7 @@ bool OurReader::decodeString(Token& token) {
   return true;
 }
 
-bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {
+bool OurReader::decodeString(Token& token, String& decoded) {
   decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
   Location current = token.start_ + 1; // skip '"'
   Location end = token.end_ - 1;       // do not include '"'
@@ -1678,7 +1674,7 @@ bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {
     Char c = *current++;
     if (c == '"')
       break;
-    else if (c == '\\') {
+    if (c == '\\') {
       if (current == end)
         return addError("Empty escape sequence in string", token, current);
       Char escape = *current++;
@@ -1723,10 +1719,8 @@ bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {
   return true;
 }
 
-bool OurReader::decodeUnicodeCodePoint(Token& token,
-                                    Location& current,
-                                    Location end,
-                                    unsigned int& unicode) {
+bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
+                                       Location end, unsigned int& unicode) {
 
   unicode = 0; // Convince clang-analyzer that this is initialized before use.
   if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
@@ -1736,10 +1730,9 @@ bool OurReader::decodeUnicodeCodePoint(Token& token,
     if (end - current < 6)
       return addError(
           "additional six characters expected to parse unicode surrogate pair.",
-          token,
-          current);
-    unsigned int surrogatePair;
+          token, current);
     if (*(current++) == '\\' && *(current++) == 'u') {
+      unsigned int surrogatePair;
       if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
         unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
       } else
@@ -1747,20 +1740,17 @@ bool OurReader::decodeUnicodeCodePoint(Token& token,
     } else
       return addError("expecting another \\u token to begin the second half of "
                       "a unicode surrogate pair",
-                      token,
-                      current);
+                      token, current);
   }
   return true;
 }
 
-bool OurReader::decodeUnicodeEscapeSequence(Token& token,
-                                         Location& current,
-                                         Location end,
-                                         unsigned int& ret_unicode) {
+bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
+                                            Location end,
+                                            unsigned int& ret_unicode) {
   if (end - current < 4)
     return addError(
-        "Bad unicode escape sequence in string: four digits expected.",
-        token,
+        "Bad unicode escape sequence in string: four digits expected.", token,
         current);
   int unicode = 0;
   for (int index = 0; index < 4; ++index) {
@@ -1775,15 +1765,13 @@ bool OurReader::decodeUnicodeEscapeSequence(Token& token,
     else
       return addError(
           "Bad unicode escape sequence in string: hexadecimal digit expected.",
-          token,
-          current);
+          token, current);
   }
   ret_unicode = static_cast<unsigned int>(unicode);
   return true;
 }
 
-bool
-OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
+bool OurReader::addError(const String& message, Token& token, Location extra) {
   ErrorInfo info;
   info.token_ = token;
   info.message_ = message;
@@ -1805,9 +1793,8 @@ bool OurReader::recoverFromError(TokenType skipUntilToken) {
   return false;
 }
 
-bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message,
-                                Token& token,
-                                TokenType skipUntilToken) {
+bool OurReader::addErrorAndRecover(const String& message, Token& token,
+                                   TokenType skipUntilToken) {
   addError(message, token);
   return recoverFromError(skipUntilToken);
 }
@@ -1820,9 +1807,8 @@ OurReader::Char OurReader::getNextChar() {
   return *current_++;
 }
 
-void OurReader::getLocationLineAndColumn(Location location,
-                                      int& line,
-                                      int& column) const {
+void OurReader::getLocationLineAndColumn(Location location, int& line,
+                                         int& column) const {
   Location current = begin_;
   Location lastLineStart = current;
   line = 0;
@@ -1843,20 +1829,17 @@ void OurReader::getLocationLineAndColumn(Location location,
   ++line;
 }
 
-JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const {
+String OurReader::getLocationLineAndColumn(Location location) const {
   int line, column;
   getLocationLineAndColumn(location, line, column);
   char buffer[18 + 16 + 16 + 1];
-  snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+  jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
   return buffer;
 }
 
-JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
-  JSONCPP_STRING formattedMessage;
-  for (Errors::const_iterator itError = errors_.begin();
-       itError != errors_.end();
-       ++itError) {
-    const ErrorInfo& error = *itError;
+String OurReader::getFormattedErrorMessages() const {
+  String formattedMessage;
+  for (const auto& error : errors_) {
     formattedMessage +=
         "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
     formattedMessage += "  " + error.message_ + "\n";
@@ -1869,10 +1852,7 @@ JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
 
 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
   std::vector<OurReader::StructuredError> allErrors;
-  for (Errors::const_iterator itError = errors_.begin();
-       itError != errors_.end();
-       ++itError) {
-    const ErrorInfo& error = *itError;
+  for (const auto& error : errors_) {
     OurReader::StructuredError structured;
     structured.offset_start = error.token_.start_ - begin_;
     structured.offset_limit = error.token_.end_ - begin_;
@@ -1882,59 +1862,15 @@ std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
   return allErrors;
 }
 
-bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) {
-  ptrdiff_t length = end_ - begin_;
-  if(value.getOffsetStart() > length
-    || value.getOffsetLimit() > length)
-    return false;
-  Token token;
-  token.type_ = tokenError;
-  token.start_ = begin_ + value.getOffsetStart();
-  token.end_ = end_ + value.getOffsetLimit();
-  ErrorInfo info;
-  info.token_ = token;
-  info.message_ = message;
-  info.extra_ = 0;
-  errors_.push_back(info);
-  return true;
-}
-
-bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
-  ptrdiff_t length = end_ - begin_;
-  if(value.getOffsetStart() > length
-    || value.getOffsetLimit() > length
-    || extra.getOffsetLimit() > length)
-    return false;
-  Token token;
-  token.type_ = tokenError;
-  token.start_ = begin_ + value.getOffsetStart();
-  token.end_ = begin_ + value.getOffsetLimit();
-  ErrorInfo info;
-  info.token_ = token;
-  info.message_ = message;
-  info.extra_ = begin_ + extra.getOffsetStart();
-  errors_.push_back(info);
-  return true;
-}
-
-bool OurReader::good() const {
-  return !errors_.size();
-}
-
-
 class OurCharReader : public CharReader {
   bool const collectComments_;
   OurReader reader_;
+
 public:
-  OurCharReader(
-    bool collectComments,
-    OurFeatures const& features)
-  : collectComments_(collectComments)
-  , reader_(features)
-  {}
-  bool parse(
-      char const* beginDoc, char const* endDoc,
-      Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE {
+  OurCharReader(bool collectComments, OurFeatures const& features)
+      : collectComments_(collectComments), reader_(features) {}
+  bool parse(char const* beginDoc, char const* endDoc, Value* root,
+             String* errs) override {
     bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
     if (errs) {
       *errs = reader_.getFormattedErrorMessages();
@@ -1943,67 +1879,64 @@ public:
   }
 };
 
-CharReaderBuilder::CharReaderBuilder()
-{
-  setDefaults(&settings_);
-}
-CharReaderBuilder::~CharReaderBuilder()
-{}
-CharReader* CharReaderBuilder::newCharReader() const
-{
+CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
+CharReaderBuilder::~CharReaderBuilder() = default;
+CharReader* CharReaderBuilder::newCharReader() const {
   bool collectComments = settings_["collectComments"].asBool();
   OurFeatures features = OurFeatures::all();
   features.allowComments_ = settings_["allowComments"].asBool();
+  features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();
   features.strictRoot_ = settings_["strictRoot"].asBool();
-  features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
+  features.allowDroppedNullPlaceholders_ =
+      settings_["allowDroppedNullPlaceholders"].asBool();
   features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
   features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
-  features.stackLimit_ = settings_["stackLimit"].asInt();
+
+  // Stack limit is always a size_t, so we get this as an unsigned int
+  // regardless of it we have 64-bit integer support enabled.
+  features.stackLimit_ = static_cast<size_t>(settings_["stackLimit"].asUInt());
   features.failIfExtra_ = settings_["failIfExtra"].asBool();
   features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
   features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
+  features.skipBom_ = settings_["skipBom"].asBool();
   return new OurCharReader(collectComments, features);
 }
-static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys)
-{
-  valid_keys->clear();
-  valid_keys->insert("collectComments");
-  valid_keys->insert("allowComments");
-  valid_keys->insert("strictRoot");
-  valid_keys->insert("allowDroppedNullPlaceholders");
-  valid_keys->insert("allowNumericKeys");
-  valid_keys->insert("allowSingleQuotes");
-  valid_keys->insert("stackLimit");
-  valid_keys->insert("failIfExtra");
-  valid_keys->insert("rejectDupKeys");
-  valid_keys->insert("allowSpecialFloats");
-}
-bool CharReaderBuilder::validate(Json::Value* invalid) const
-{
-  Json::Value my_invalid;
-  if (!invalid) invalid = &my_invalid;  // so we do not need to test for NULL
-  Json::Value& inv = *invalid;
-  std::set<JSONCPP_STRING> valid_keys;
-  getValidReaderKeys(&valid_keys);
-  Value::Members keys = settings_.getMemberNames();
-  size_t n = keys.size();
-  for (size_t i = 0; i < n; ++i) {
-    JSONCPP_STRING const& key = keys[i];
-    if (valid_keys.find(key) == valid_keys.end()) {
-      inv[key] = settings_[key];
-    }
+
+bool CharReaderBuilder::validate(Json::Value* invalid) const {
+  static const auto& valid_keys = *new std::set<String>{
+      "collectComments",
+      "allowComments",
+      "allowTrailingCommas",
+      "strictRoot",
+      "allowDroppedNullPlaceholders",
+      "allowNumericKeys",
+      "allowSingleQuotes",
+      "stackLimit",
+      "failIfExtra",
+      "rejectDupKeys",
+      "allowSpecialFloats",
+      "skipBom",
+  };
+  for (auto si = settings_.begin(); si != settings_.end(); ++si) {
+    auto key = si.name();
+    if (valid_keys.count(key))
+      continue;
+    if (invalid)
+      (*invalid)[std::move(key)] = *si;
+    else
+      return false;
   }
-  return 0u == inv.size();
+  return invalid ? invalid->empty() : true;
 }
-Value& CharReaderBuilder::operator[](JSONCPP_STRING key)
-{
+
+Value& CharReaderBuilder::operator[](const String& key) {
   return settings_[key];
 }
 // static
-void CharReaderBuilder::strictMode(Json::Value* settings)
-{
-//! [CharReaderBuilderStrictMode]
+void CharReaderBuilder::strictMode(Json::Value* settings) {
+  //! [CharReaderBuilderStrictMode]
   (*settings)["allowComments"] = false;
+  (*settings)["allowTrailingCommas"] = false;
   (*settings)["strictRoot"] = true;
   (*settings)["allowDroppedNullPlaceholders"] = false;
   (*settings)["allowNumericKeys"] = false;
@@ -2012,14 +1945,15 @@ void CharReaderBuilder::strictMode(Json::Value* settings)
   (*settings)["failIfExtra"] = true;
   (*settings)["rejectDupKeys"] = true;
   (*settings)["allowSpecialFloats"] = false;
-//! [CharReaderBuilderStrictMode]
+  (*settings)["skipBom"] = true;
+  //! [CharReaderBuilderStrictMode]
 }
 // static
-void CharReaderBuilder::setDefaults(Json::Value* settings)
-{
-//! [CharReaderBuilderDefaults]
+void CharReaderBuilder::setDefaults(Json::Value* settings) {
+  //! [CharReaderBuilderDefaults]
   (*settings)["collectComments"] = true;
   (*settings)["allowComments"] = true;
+  (*settings)["allowTrailingCommas"] = true;
   (*settings)["strictRoot"] = false;
   (*settings)["allowDroppedNullPlaceholders"] = false;
   (*settings)["allowNumericKeys"] = false;
@@ -2028,19 +1962,18 @@ void CharReaderBuilder::setDefaults(Json::Value* settings)
   (*settings)["failIfExtra"] = false;
   (*settings)["rejectDupKeys"] = false;
   (*settings)["allowSpecialFloats"] = false;
-//! [CharReaderBuilderDefaults]
+  (*settings)["skipBom"] = true;
+  //! [CharReaderBuilderDefaults]
 }
 
 //////////////////////////////////
 // global functions
 
-bool parseFromStream(
-    CharReader::Factory const& fact, JSONCPP_ISTREAM& sin,
-    Value* root, JSONCPP_STRING* errs)
-{
-  JSONCPP_OSTRINGSTREAM ssin;
+bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
+                     String* errs) {
+  OStringStream ssin;
   ssin << sin.rdbuf();
-  JSONCPP_STRING doc = ssin.str();
+  String doc = ssin.str();
   char const* begin = doc.data();
   char const* end = begin + doc.size();
   // Note that we do not actually need a null-terminator.
@@ -2048,15 +1981,11 @@ bool parseFromStream(
   return reader->parse(begin, end, root, errs);
 }
 
-JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {
+IStream& operator>>(IStream& sin, Value& root) {
   CharReaderBuilder b;
-  JSONCPP_STRING errs;
+  String errs;
   bool ok = parseFromStream(b, sin, &root, &errs);
   if (!ok) {
-    fprintf(stderr,
-            "Error from reader: %s",
-            errs.c_str());
-
     throwRuntimeError(errs);
   }
   return sin;
index 4316178..2d7b7d9 100644 (file)
@@ -6,6 +6,9 @@
 #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
 #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
 
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/config.h>
+#endif
 
 // Also support old flag NO_LOCALE_SUPPORT
 #ifdef NO_LOCALE_SUPPORT
@@ -23,7 +26,7 @@
  */
 
 namespace Json {
-static char getDecimalPoint() {
+static inline char getDecimalPoint() {
 #ifdef JSONCPP_NO_LOCALE_SUPPORT
   return '\0';
 #else
@@ -33,8 +36,8 @@ static char getDecimalPoint() {
 }
 
 /// Converts a unicode code-point to UTF-8.
-static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) {
-  JSONCPP_STRING result;
+static inline String codePointToUTF8(unsigned int cp) {
+  String result;
 
   // based on description from http://en.wikipedia.org/wiki/UTF-8
 
@@ -61,9 +64,6 @@ static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) {
   return result;
 }
 
-/// Returns true if ch is a control character (in range [1,31]).
-static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
-
 enum {
   /// Constant that specify the size of the buffer that must be passed to
   /// uintToString.
@@ -71,10 +71,10 @@ enum {
 };
 
 // Defines a char buffer for use with uintToString().
-typedef char UIntToStringBuffer[uintToStringBufferSize];
+using UIntToStringBuffer = char[uintToStringBufferSize];
 
 /** Converts an unsigned integer to string.
- * @param value Unsigned interger to convert to string
+ * @param value Unsigned integer to convert to string
  * @param current Input/Output string buffer.
  *        Must have at least uintToStringBufferSize chars free.
  */
@@ -91,27 +91,44 @@ static inline void uintToString(LargestUInt value, char*& current) {
  * We had a sophisticated way, but it did not work in WinCE.
  * @see https://github.com/open-source-parsers/jsoncpp/pull/9
  */
-static inline void fixNumericLocale(char* begin, char* end) {
-  while (begin < end) {
+template <typename Iter> Iter fixNumericLocale(Iter begin, Iter end) {
+  for (; begin != end; ++begin) {
     if (*begin == ',') {
       *begin = '.';
     }
-    ++begin;
   }
+  return begin;
 }
 
-static inline void fixNumericLocaleInput(char* begin, char* end) {
+template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
   char decimalPoint = getDecimalPoint();
-  if (decimalPoint != '\0' && decimalPoint != '.') {
-    while (begin < end) {
-      if (*begin == '.') {
-        *begin = decimalPoint;
-      }
-      ++begin;
+  if (decimalPoint == '\0' || decimalPoint == '.') {
+    return;
+  }
+  for (; begin != end; ++begin) {
+    if (*begin == '.') {
+      *begin = decimalPoint;
+    }
+  }
+}
+
+/**
+ * Return iterator that would be the new end of the range [begin,end), if we
+ * were to delete zeros in the end of string, but not the last zero before '.'.
+ */
+template <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) {
+  for (; begin != end; --end) {
+    if (*(end - 1) != '0') {
+      return end;
+    }
+    // Don't delete the last zero before the decimal point.
+    if (begin != (end - 1) && *(end - 2) == '.') {
+      return end;
     }
   }
+  return end;
 }
 
-} // namespace Json {
+} // namespace Json
 
 #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
index f271e57..d59b7d9 100644 (file)
@@ -8,20 +8,54 @@
 #include <json/value.h>
 #include <json/writer.h>
 #endif // if !defined(JSON_IS_AMALGAMATION)
-#include <math.h>
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
+#include <iostream>
 #include <sstream>
 #include <utility>
-#include <string.h>
-#include <assert.h>
-#ifdef JSON_USE_CPPTL
-#include <cpptl/conststring.h>
+
+// Provide implementation equivalent of std::snprintf for older _MSC compilers
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#include <stdarg.h>
+static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size,
+                                      const char* format, va_list ap) {
+  int count = -1;
+  if (size != 0)
+    count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
+  if (count == -1)
+    count = _vscprintf(format, ap);
+  return count;
+}
+
+int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
+                                       const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap);
+  va_end(ap);
+  return count;
+}
+#endif
+
+// Disable warning C4702 : unreachable code
+#if defined(_MSC_VER)
+#pragma warning(disable : 4702)
 #endif
-#include <cstddef> // size_t
-#include <algorithm> // min()
 
 #define JSON_ASSERT_UNREACHABLE assert(false)
 
 namespace Json {
+template <typename T>
+static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {
+  std::unique_ptr<T> r;
+  if (p) {
+    r = std::unique_ptr<T>(new T(*p));
+  }
+  return r;
+}
 
 // This is a walkaround to avoid the static initialization of Value::null.
 // kNull must be word-aligned to avoid crashing on ARM.  We use an alignment of
@@ -31,50 +65,34 @@ namespace Json {
 #else
 #define ALIGNAS(byte_alignment)
 #endif
-//static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
-//const unsigned char& kNullRef = kNull[0];
-//const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
-//const Value& Value::nullRef = null;
 
 // static
-Value const& Value::nullSingleton()
-{
- static Value const nullStatic;
- return nullStatic;
+Value const& Value::nullSingleton() {
+  static Value const nullStatic;
+  return nullStatic;
 }
 
-// for backwards compatibility, we'll leave these global references around, but DO NOT
-// use them in JSONCPP library code any more!
+#if JSON_USE_NULLREF
+// for backwards compatibility, we'll leave these global references around, but
+// DO NOT use them in JSONCPP library code any more!
+// static
 Value const& Value::null = Value::nullSingleton();
-Value const& Value::nullRef = Value::nullSingleton();
 
-const Int Value::minInt = Int(~(UInt(-1) / 2));
-const Int Value::maxInt = Int(UInt(-1) / 2);
-const UInt Value::maxUInt = UInt(-1);
-#if defined(JSON_HAS_INT64)
-const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
-const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
-const UInt64 Value::maxUInt64 = UInt64(-1);
-// The constant is hard-coded because some compiler have trouble
-// converting Value::maxUInt64 to a double correctly (AIX/xlC).
-// Assumes that UInt64 is a 64 bits integer.
-static const double maxUInt64AsDouble = 18446744073709551615.0;
-#endif // defined(JSON_HAS_INT64)
-const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
-const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
-const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
+// static
+Value const& Value::nullRef = Value::nullSingleton();
+#endif
 
 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
 template <typename T, typename U>
 static inline bool InRange(double d, T min, U max) {
   // The casts can lose precision, but we are looking only for
   // an approximate range. Might fail on edge cases though. ~cdunn
-  //return d >= static_cast<double>(min) && d <= static_cast<double>(max);
-  return d >= min && d <= max;
+  return d >= static_cast<double>(min) && d <= static_cast<double>(max);
 }
 #else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
 static inline double integerToDouble(Json::UInt64 value) {
-  return static_cast<double>(Int64(value / 2)) * 2.0 + static_cast<double>(Int64(value & 1));
+  return static_cast<double>(Int64(value / 2)) * 2.0 +
+         static_cast<double>(Int64(value & 1));
 }
 
 template <typename T> static inline double integerToDouble(T value) {
@@ -94,19 +112,16 @@ static inline bool InRange(double d, T min, U max) {
  *               computed using strlen(value).
  * @return Pointer on the duplicate instance of string.
  */
-static inline char* duplicateStringValue(const char* value,
-                                         size_t length)
-{
+static inline char* duplicateStringValue(const char* value, size_t length) {
   // Avoid an integer overflow in the call to malloc below by limiting length
   // to a sane value.
   if (length >= static_cast<size_t>(Value::maxInt))
     length = Value::maxInt - 1;
 
-  char* newString = static_cast<char*>(malloc(length + 1));
-  if (newString == NULL) {
-    throwRuntimeError(
-        "in Json::Value::duplicateStringValue(): "
-        "Failed to allocate string value buffer");
+  auto newString = static_cast<char*>(malloc(length + 1));
+  if (newString == nullptr) {
+    throwRuntimeError("in Json::Value::duplicateStringValue(): "
+                      "Failed to allocate string value buffer");
   }
   memcpy(newString, value, length);
   newString[length] = 0;
@@ -115,31 +130,28 @@ static inline char* duplicateStringValue(const char* value,
 
 /* Record the length as a prefix.
  */
-static inline char* duplicateAndPrefixStringValue(
-    const char* value,
-    unsigned int length)
-{
+static inline char* duplicateAndPrefixStringValue(const char* value,
+                                                  unsigned int length) {
   // Avoid an integer overflow in the call to malloc below by limiting length
   // to a sane value.
-  JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) - sizeof(unsigned) - 1U,
+  JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) -
+                                    sizeof(unsigned) - 1U,
                       "in Json::Value::duplicateAndPrefixStringValue(): "
                       "length too big for prefixing");
-  unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
-  char* newString = static_cast<char*>(malloc(actualLength));
-  if (newString == 0) {
-    throwRuntimeError(
-        "in Json::Value::duplicateAndPrefixStringValue(): "
-        "Failed to allocate string value buffer");
+  size_t actualLength = sizeof(length) + length + 1;
+  auto newString = static_cast<char*>(malloc(actualLength));
+  if (newString == nullptr) {
+    throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
+                      "Failed to allocate string value buffer");
   }
   *reinterpret_cast<unsigned*>(newString) = length;
   memcpy(newString + sizeof(unsigned), value, length);
-  newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
+  newString[actualLength - 1U] =
+      0; // to avoid buffer over-run accidents by users later
   return newString;
 }
-inline static void decodePrefixedString(
-    bool isPrefixed, char const* prefixed,
-    unsigned* length, char const** value)
-{
+inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
+                                        unsigned* length, char const** value) {
   if (!isPrefixed) {
     *length = static_cast<unsigned>(strlen(prefixed));
     *value = prefixed;
@@ -148,7 +160,8 @@ inline static void decodePrefixedString(
     *value = prefixed + sizeof(unsigned);
   }
 }
-/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
+/** Free the string duplicated by
+ * duplicateStringValue()/duplicateAndPrefixStringValue().
  */
 #if JSONCPP_USING_SECURE_MEMORY
 static inline void releasePrefixedStringValue(char* value) {
@@ -161,17 +174,13 @@ static inline void releasePrefixedStringValue(char* value) {
 }
 static inline void releaseStringValue(char* value, unsigned length) {
   // length==0 => we allocated the strings memory
-  size_t size = (length==0) ? strlen(value) : length;
+  size_t size = (length == 0) ? strlen(value) : length;
   memset(value, 0, size);
   free(value);
 }
-#else // !JSONCPP_USING_SECURE_MEMORY
-static inline void releasePrefixedStringValue(char* value) {
-  free(value);
-}
-static inline void releaseStringValue(char* value, unsigned) {
-  free(value);
-}
+#else  // !JSONCPP_USING_SECURE_MEMORY
+static inline void releasePrefixedStringValue(char* value) { free(value); }
+static inline void releaseStringValue(char* value, unsigned) { free(value); }
 #endif // JSONCPP_USING_SECURE_MEMORY
 
 } // namespace Json
@@ -190,58 +199,28 @@ static inline void releaseStringValue(char* value, unsigned) {
 
 namespace Json {
 
-Exception::Exception(JSONCPP_STRING const& msg)
-  : msg_(msg)
-{}
-Exception::~Exception() JSONCPP_NOEXCEPT
-{}
-char const* Exception::what() const JSONCPP_NOEXCEPT
-{
-  return msg_.c_str();
-}
-RuntimeError::RuntimeError(JSONCPP_STRING const& msg)
-  : Exception(msg)
-{}
-LogicError::LogicError(JSONCPP_STRING const& msg)
-  : Exception(msg)
-{}
-JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg)
-{
+#if JSON_USE_EXCEPTION
+Exception::Exception(String msg) : msg_(std::move(msg)) {}
+Exception::~Exception() noexcept = default;
+char const* Exception::what() const noexcept { return msg_.c_str(); }
+RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
+LogicError::LogicError(String const& msg) : Exception(msg) {}
+JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
   throw RuntimeError(msg);
 }
-JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg)
-{
+JSONCPP_NORETURN void throwLogicError(String const& msg) {
   throw LogicError(msg);
 }
-
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// class Value::CommentInfo
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-// //////////////////////////////////////////////////////////////////
-
-Value::CommentInfo::CommentInfo() : comment_(0)
-{}
-
-Value::CommentInfo::~CommentInfo() {
-  if (comment_)
-    releaseStringValue(comment_, 0u);
+#else // !JSON_USE_EXCEPTION
+JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
+  std::cerr << msg << std::endl;
+  abort();
 }
-
-void Value::CommentInfo::setComment(const char* text, size_t len) {
-  if (comment_) {
-    releaseStringValue(comment_, 0u);
-    comment_ = 0;
-  }
-  JSON_ASSERT(text != 0);
-  JSON_ASSERT_MESSAGE(
-      text[0] == '\0' || text[0] == '/',
-      "in Json::Value::setComment(): Comments must start with /");
-  // It seems that /**/ style comments are acceptable as well.
-  comment_ = duplicateStringValue(text, len);
+JSONCPP_NORETURN void throwLogicError(String const& msg) {
+  std::cerr << msg << std::endl;
+  abort();
 }
+#endif
 
 // //////////////////////////////////////////////////////////////////
 // //////////////////////////////////////////////////////////////////
@@ -254,36 +233,44 @@ void Value::CommentInfo::setComment(const char* text, size_t len) {
 // Notes: policy_ indicates if the string was allocated when
 // a string is stored.
 
-Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {}
+Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}
 
-Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate)
+Value::CZString::CZString(char const* str, unsigned length,
+                          DuplicationPolicy allocate)
     : cstr_(str) {
   // allocate != duplicate
   storage_.policy_ = allocate & 0x3;
-  storage_.length_ = ulength & 0x3FFFFFFF;
+  storage_.length_ = length & 0x3FFFFFFF;
 }
 
 Value::CZString::CZString(const CZString& other) {
-  cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0
-                                ? duplicateStringValue(other.cstr_, other.storage_.length_)
-                                : other.cstr_);
-  storage_.policy_ = static_cast<unsigned>(other.cstr_
-                 ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication
-                     ? noDuplication : duplicate)
-                 : static_cast<DuplicationPolicy>(other.storage_.policy_)) & 3U;
+  cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
+               ? duplicateStringValue(other.cstr_, other.storage_.length_)
+               : other.cstr_);
+  storage_.policy_ =
+      static_cast<unsigned>(
+          other.cstr_
+              ? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
+                         noDuplication
+                     ? noDuplication
+                     : duplicate)
+              : static_cast<DuplicationPolicy>(other.storage_.policy_)) &
+      3U;
   storage_.length_ = other.storage_.length_;
 }
 
-#if JSON_HAS_RVALUE_REFERENCES
 Value::CZString::CZString(CZString&& other)
-  : cstr_(other.cstr_), index_(other.index_) {
+    : cstr_(other.cstr_), index_(other.index_) {
   other.cstr_ = nullptr;
 }
-#endif
 
 Value::CZString::~CZString() {
   if (cstr_ && storage_.policy_ == duplicate) {
-         releaseStringValue(const_cast<char*>(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary
+    releaseStringValue(const_cast<char*>(cstr_),
+                       storage_.length_ + 1U); // +1 for null terminating
+                                               // character for sake of
+                                               // completeness but not actually
+                                               // necessary
   }
 }
 
@@ -298,36 +285,39 @@ Value::CZString& Value::CZString::operator=(const CZString& other) {
   return *this;
 }
 
-#if JSON_HAS_RVALUE_REFERENCES
 Value::CZString& Value::CZString::operator=(CZString&& other) {
   cstr_ = other.cstr_;
   index_ = other.index_;
   other.cstr_ = nullptr;
   return *this;
 }
-#endif
 
 bool Value::CZString::operator<(const CZString& other) const {
-  if (!cstr_) return index_ < other.index_;
-  //return strcmp(cstr_, other.cstr_) < 0;
+  if (!cstr_)
+    return index_ < other.index_;
+  // return strcmp(cstr_, other.cstr_) < 0;
   // Assume both are strings.
   unsigned this_len = this->storage_.length_;
   unsigned other_len = other.storage_.length_;
   unsigned min_len = std::min<unsigned>(this_len, other_len);
   JSON_ASSERT(this->cstr_ && other.cstr_);
   int comp = memcmp(this->cstr_, other.cstr_, min_len);
-  if (comp < 0) return true;
-  if (comp > 0) return false;
+  if (comp < 0)
+    return true;
+  if (comp > 0)
+    return false;
   return (this_len < other_len);
 }
 
 bool Value::CZString::operator==(const CZString& other) const {
-  if (!cstr_) return index_ == other.index_;
-  //return strcmp(cstr_, other.cstr_) == 0;
+  if (!cstr_)
+    return index_ == other.index_;
+  // return strcmp(cstr_, other.cstr_) == 0;
   // Assume both are strings.
   unsigned this_len = this->storage_.length_;
   unsigned other_len = other.storage_.length_;
-  if (this_len != other_len) return false;
+  if (this_len != other_len)
+    return false;
   JSON_ASSERT(this->cstr_ && other.cstr_);
   int comp = memcmp(this->cstr_, other.cstr_, this_len);
   return comp == 0;
@@ -335,10 +325,12 @@ bool Value::CZString::operator==(const CZString& other) const {
 
 ArrayIndex Value::CZString::index() const { return index_; }
 
-//const char* Value::CZString::c_str() const { return cstr_; }
+// const char* Value::CZString::c_str() const { return cstr_; }
 const char* Value::CZString::data() const { return cstr_; }
 unsigned Value::CZString::length() const { return storage_.length_; }
-bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; }
+bool Value::CZString::isStaticString() const {
+  return storage_.policy_ == noDuplication;
+}
 
 // //////////////////////////////////////////////////////////////////
 // //////////////////////////////////////////////////////////////////
@@ -352,10 +344,10 @@ bool Value::CZString::isStaticString() const { return storage_.policy_ == noDupl
  * memset( this, 0, sizeof(Value) )
  * This optimization is used in ValueInternalMap fast allocator.
  */
-Value::Value(ValueType vtype) {
+Value::Value(ValueType type) {
   static char const emptyString[] = "";
-  initBasic(vtype);
-  switch (vtype) {
+  initBasic(type);
+  switch (type) {
   case nullValue:
     break;
   case intValue:
@@ -408,20 +400,22 @@ Value::Value(double value) {
 
 Value::Value(const char* value) {
   initBasic(stringValue, true);
-  JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor");
-  value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
+  JSON_ASSERT_MESSAGE(value != nullptr,
+                      "Null Value Passed to Value Constructor");
+  value_.string_ = duplicateAndPrefixStringValue(
+      value, static_cast<unsigned>(strlen(value)));
 }
 
-Value::Value(const char* beginValue, const char* endValue) {
+Value::Value(const char* begin, const char* end) {
   initBasic(stringValue, true);
   value_.string_ =
-      duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue));
+      duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));
 }
 
-Value::Value(const JSONCPP_STRING& value) {
+Value::Value(const String& value) {
   initBasic(stringValue, true);
-  value_.string_ =
-      duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
+  value_.string_ = duplicateAndPrefixStringValue(
+      value.data(), static_cast<unsigned>(value.length()));
 }
 
 Value::Value(const StaticString& value) {
@@ -429,114 +423,44 @@ Value::Value(const StaticString& value) {
   value_.string_ = const_cast<char*>(value.c_str());
 }
 
-#ifdef JSON_USE_CPPTL
-Value::Value(const CppTL::ConstString& value) {
-  initBasic(stringValue, true);
-  value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length()));
-}
-#endif
-
 Value::Value(bool value) {
   initBasic(booleanValue);
   value_.bool_ = value;
 }
 
-Value::Value(Value const& other)
-    : type_(other.type_), allocated_(false)
-      ,
-      comments_(0), start_(other.start_), limit_(other.limit_)
-{
-  switch (type_) {
-  case nullValue:
-  case intValue:
-  case uintValue:
-  case realValue:
-  case booleanValue:
-    value_ = other.value_;
-    break;
-  case stringValue:
-    if (other.value_.string_ && other.allocated_) {
-      unsigned len;
-      char const* str;
-      decodePrefixedString(other.allocated_, other.value_.string_,
-          &len, &str);
-      value_.string_ = duplicateAndPrefixStringValue(str, len);
-      allocated_ = true;
-    } else {
-      value_.string_ = other.value_.string_;
-      allocated_ = false;
-    }
-    break;
-  case arrayValue:
-  case objectValue:
-    value_.map_ = new ObjectValues(*other.value_.map_);
-    break;
-  default:
-    JSON_ASSERT_UNREACHABLE;
-  }
-  if (other.comments_) {
-    comments_ = new CommentInfo[numberOfCommentPlacement];
-    for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
-      const CommentInfo& otherComment = other.comments_[comment];
-      if (otherComment.comment_)
-        comments_[comment].setComment(
-            otherComment.comment_, strlen(otherComment.comment_));
-    }
-  }
+Value::Value(const Value& other) {
+  dupPayload(other);
+  dupMeta(other);
 }
 
-#if JSON_HAS_RVALUE_REFERENCES
-// Move constructor
 Value::Value(Value&& other) {
   initBasic(nullValue);
   swap(other);
 }
-#endif
 
 Value::~Value() {
-  switch (type_) {
-  case nullValue:
-  case intValue:
-  case uintValue:
-  case realValue:
-  case booleanValue:
-    break;
-  case stringValue:
-    if (allocated_)
-      releasePrefixedStringValue(value_.string_);
-    break;
-  case arrayValue:
-  case objectValue:
-    delete value_.map_;
-    break;
-  default:
-    JSON_ASSERT_UNREACHABLE;
-  }
-
-  delete[] comments_;
-
+  releasePayload();
   value_.uint_ = 0;
 }
 
-Value& Value::operator=(Value other) {
-  swap(other);
+Value& Value::operator=(const Value& other) {
+  Value(other).swap(*this);
+  return *this;
+}
+
+Value& Value::operator=(Value&& other) {
+  other.swap(*this);
   return *this;
 }
 
 void Value::swapPayload(Value& other) {
-  ValueType temp = type_;
-  type_ = other.type_;
-  other.type_ = temp;
+  std::swap(bits_, other.bits_);
   std::swap(value_, other.value_);
-  int temp2 = allocated_;
-  allocated_ = other.allocated_;
-  other.allocated_ = temp2 & 0x1;
 }
 
 void Value::copyPayload(const Value& other) {
-  type_ = other.type_;
-  value_ = other.value_;
-  allocated_ = other.allocated_;
+  releasePayload();
+  dupPayload(other);
 }
 
 void Value::swap(Value& other) {
@@ -548,12 +472,12 @@ void Value::swap(Value& other) {
 
 void Value::copy(const Value& other) {
   copyPayload(other);
-  comments_ = other.comments_;
-  start_ = other.start_;
-  limit_ = other.limit_;
+  dupMeta(other);
 }
 
-ValueType Value::type() const { return type_; }
+ValueType Value::type() const {
+  return static_cast<ValueType>(bits_.value_type_);
+}
 
 int Value::compare(const Value& other) const {
   if (*this < other)
@@ -564,10 +488,10 @@ int Value::compare(const Value& other) const {
 }
 
 bool Value::operator<(const Value& other) const {
-  int typeDelta = type_ - other.type_;
+  int typeDelta = type() - other.type();
   if (typeDelta)
-    return typeDelta < 0 ? true : false;
-  switch (type_) {
+    return typeDelta < 0;
+  switch (type()) {
   case nullValue:
     return false;
   case intValue:
@@ -578,30 +502,33 @@ bool Value::operator<(const Value& other) const {
     return value_.real_ < other.value_.real_;
   case booleanValue:
     return value_.bool_ < other.value_.bool_;
-  case stringValue:
-  {
-    if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
-      if (other.value_.string_) return true;
-      else return false;
+  case stringValue: {
+    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
+      return other.value_.string_ != nullptr;
     }
     unsigned this_len;
     unsigned other_len;
     char const* this_str;
     char const* other_str;
-    decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
-    decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
+    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
+                         &this_str);
+    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
+                         &other_str);
     unsigned min_len = std::min<unsigned>(this_len, other_len);
     JSON_ASSERT(this_str && other_str);
     int comp = memcmp(this_str, other_str, min_len);
-    if (comp < 0) return true;
-    if (comp > 0) return false;
+    if (comp < 0)
+      return true;
+    if (comp > 0)
+      return false;
     return (this_len < other_len);
   }
   case arrayValue:
   case objectValue: {
-    int delta = int(value_.map_->size() - other.value_.map_->size());
-    if (delta)
-      return delta < 0;
+    auto thisSize = value_.map_->size();
+    auto otherSize = other.value_.map_->size();
+    if (thisSize != otherSize)
+      return thisSize < otherSize;
     return (*value_.map_) < (*other.value_.map_);
   }
   default:
@@ -617,14 +544,9 @@ bool Value::operator>=(const Value& other) const { return !(*this < other); }
 bool Value::operator>(const Value& other) const { return other < *this; }
 
 bool Value::operator==(const Value& other) const {
-  // if ( type_ != other.type_ )
-  // GCC 2.95.3 says:
-  // attempt to take address of bit-field structure member `Json::Value::type_'
-  // Beats me, but a temp solves the problem.
-  int temp = other.type_;
-  if (type_ != temp)
+  if (type() != other.type())
     return false;
-  switch (type_) {
+  switch (type()) {
   case nullValue:
     return true;
   case intValue:
@@ -635,18 +557,20 @@ bool Value::operator==(const Value& other) const {
     return value_.real_ == other.value_.real_;
   case booleanValue:
     return value_.bool_ == other.value_.bool_;
-  case stringValue:
-  {
-    if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
+  case stringValue: {
+    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
       return (value_.string_ == other.value_.string_);
     }
     unsigned this_len;
     unsigned other_len;
     char const* this_str;
     char const* other_str;
-    decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
-    decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
-    if (this_len != other_len) return false;
+    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
+                         &this_str);
+    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
+                         &other_str);
+    if (this_len != other_len)
+      return false;
     JSON_ASSERT(this_str && other_str);
     int comp = memcmp(this_str, other_str, this_len);
     return comp == 0;
@@ -664,47 +588,55 @@ bool Value::operator==(const Value& other) const {
 bool Value::operator!=(const Value& other) const { return !(*this == other); }
 
 const char* Value::asCString() const {
-  JSON_ASSERT_MESSAGE(type_ == stringValue,
+  JSON_ASSERT_MESSAGE(type() == stringValue,
                       "in Json::Value::asCString(): requires stringValue");
-  if (value_.string_ == 0) return 0;
+  if (value_.string_ == nullptr)
+    return nullptr;
   unsigned this_len;
   char const* this_str;
-  decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
+                       &this_str);
   return this_str;
 }
 
 #if JSONCPP_USING_SECURE_MEMORY
 unsigned Value::getCStringLength() const {
-  JSON_ASSERT_MESSAGE(type_ == stringValue,
-                         "in Json::Value::asCString(): requires stringValue");
-  if (value_.string_ == 0) return 0;
+  JSON_ASSERT_MESSAGE(type() == stringValue,
+                      "in Json::Value::asCString(): requires stringValue");
+  if (value_.string_ == 0)
+    return 0;
   unsigned this_len;
   char const* this_str;
-  decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
+                       &this_str);
   return this_len;
 }
 #endif
 
-bool Value::getString(char const** str, char const** cend) const {
-  if (type_ != stringValue) return false;
-  if (value_.string_ == 0) return false;
+bool Value::getString(char const** begin, char const** end) const {
+  if (type() != stringValue)
+    return false;
+  if (value_.string_ == nullptr)
+    return false;
   unsigned length;
-  decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
-  *cend = *str + length;
+  decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
+                       begin);
+  *end = *begin + length;
   return true;
 }
 
-JSONCPP_STRING Value::asString() const {
-  switch (type_) {
+String Value::asString() const {
+  switch (type()) {
   case nullValue:
     return "";
-  case stringValue:
-  {
-    if (value_.string_ == 0) return "";
+  case stringValue: {
+    if (value_.string_ == nullptr)
+      return "";
     unsigned this_len;
     char const* this_str;
-    decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
-    return JSONCPP_STRING(this_str, this_len);
+    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
+                         &this_str);
+    return String(this_str, this_len);
   }
   case booleanValue:
     return value_.bool_ ? "true" : "false";
@@ -719,18 +651,8 @@ JSONCPP_STRING Value::asString() const {
   }
 }
 
-#ifdef JSON_USE_CPPTL
-CppTL::ConstString Value::asConstString() const {
-  unsigned len;
-  char const* str;
-  decodePrefixedString(allocated_, value_.string_,
-      &len, &str);
-  return CppTL::ConstString(str, len);
-}
-#endif
-
 Value::Int Value::asInt() const {
-  switch (type_) {
+  switch (type()) {
   case intValue:
     JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
     return Int(value_.int_);
@@ -752,7 +674,7 @@ Value::Int Value::asInt() const {
 }
 
 Value::UInt Value::asUInt() const {
-  switch (type_) {
+  switch (type()) {
   case intValue:
     JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
     return UInt(value_.int_);
@@ -776,7 +698,7 @@ Value::UInt Value::asUInt() const {
 #if defined(JSON_HAS_INT64)
 
 Value::Int64 Value::asInt64() const {
-  switch (type_) {
+  switch (type()) {
   case intValue:
     return Int64(value_.int_);
   case uintValue:
@@ -797,7 +719,7 @@ Value::Int64 Value::asInt64() const {
 }
 
 Value::UInt64 Value::asUInt64() const {
-  switch (type_) {
+  switch (type()) {
   case intValue:
     JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
     return UInt64(value_.int_);
@@ -835,7 +757,7 @@ LargestUInt Value::asLargestUInt() const {
 }
 
 double Value::asDouble() const {
-  switch (type_) {
+  switch (type()) {
   case intValue:
     return static_cast<double>(value_.int_);
   case uintValue:
@@ -857,7 +779,7 @@ double Value::asDouble() const {
 }
 
 float Value::asFloat() const {
-  switch (type_) {
+  switch (type()) {
   case intValue:
     return static_cast<float>(value_.int_);
   case uintValue:
@@ -872,7 +794,7 @@ float Value::asFloat() const {
   case nullValue:
     return 0.0;
   case booleanValue:
-    return value_.bool_ ? 1.0f : 0.0f;
+    return value_.bool_ ? 1.0F : 0.0F;
   default:
     break;
   }
@@ -880,18 +802,20 @@ float Value::asFloat() const {
 }
 
 bool Value::asBool() const {
-  switch (type_) {
+  switch (type()) {
   case booleanValue:
     return value_.bool_;
   case nullValue:
     return false;
   case intValue:
-    return value_.int_ ? true : false;
+    return value_.int_ != 0;
   case uintValue:
-    return value_.uint_ ? true : false;
-  case realValue:
-    // This is kind of strange. Not recommended.
-    return (value_.real_ != 0.0) ? true : false;
+    return value_.uint_ != 0;
+  case realValue: {
+    // According to JavaScript language zero or NaN is regarded as false
+    const auto value_classification = std::fpclassify(value_.real_);
+    return value_classification != FP_ZERO && value_classification != FP_NAN;
+  }
   default:
     break;
   }
@@ -902,30 +826,30 @@ bool Value::isConvertibleTo(ValueType other) const {
   switch (other) {
   case nullValue:
     return (isNumeric() && asDouble() == 0.0) ||
-           (type_ == booleanValue && value_.bool_ == false) ||
-           (type_ == stringValue && asString().empty()) ||
-           (type_ == arrayValue && value_.map_->size() == 0) ||
-           (type_ == objectValue && value_.map_->size() == 0) ||
-           type_ == nullValue;
+           (type() == booleanValue && !value_.bool_) ||
+           (type() == stringValue && asString().empty()) ||
+           (type() == arrayValue && value_.map_->empty()) ||
+           (type() == objectValue && value_.map_->empty()) ||
+           type() == nullValue;
   case intValue:
     return isInt() ||
-           (type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||
-           type_ == booleanValue || type_ == nullValue;
+           (type() == realValue && InRange(value_.real_, minInt, maxInt)) ||
+           type() == booleanValue || type() == nullValue;
   case uintValue:
     return isUInt() ||
-           (type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||
-           type_ == booleanValue || type_ == nullValue;
+           (type() == realValue && InRange(value_.real_, 0, maxUInt)) ||
+           type() == booleanValue || type() == nullValue;
   case realValue:
-    return isNumeric() || type_ == booleanValue || type_ == nullValue;
+    return isNumeric() || type() == booleanValue || type() == nullValue;
   case booleanValue:
-    return isNumeric() || type_ == booleanValue || type_ == nullValue;
+    return isNumeric() || type() == booleanValue || type() == nullValue;
   case stringValue:
-    return isNumeric() || type_ == booleanValue || type_ == stringValue ||
-           type_ == nullValue;
+    return isNumeric() || type() == booleanValue || type() == stringValue ||
+           type() == nullValue;
   case arrayValue:
-    return type_ == arrayValue || type_ == nullValue;
+    return type() == arrayValue || type() == nullValue;
   case objectValue:
-    return type_ == objectValue || type_ == nullValue;
+    return type() == objectValue || type() == nullValue;
   }
   JSON_ASSERT_UNREACHABLE;
   return false;
@@ -933,7 +857,7 @@ bool Value::isConvertibleTo(ValueType other) const {
 
 /// Number of values in array or object
 ArrayIndex Value::size() const {
-  switch (type_) {
+  switch (type()) {
   case nullValue:
   case intValue:
   case uintValue:
@@ -957,20 +881,19 @@ ArrayIndex Value::size() const {
 
 bool Value::empty() const {
   if (isNull() || isArray() || isObject())
-    return size() == 0u;
-  else
-    return false;
+    return size() == 0U;
+  return false;
 }
 
-bool Value::operator!() const { return isNull(); }
+Value::operator bool() const { return !isNull(); }
 
 void Value::clear() {
-  JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
-                          type_ == objectValue,
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||
+                          type() == objectValue,
                       "in Json::Value::clear(): requires complex value");
   start_ = 0;
   limit_ = 0;
-  switch (type_) {
+  switch (type()) {
   case arrayValue:
   case objectValue:
     value_.map_->clear();
@@ -981,15 +904,15 @@ void Value::clear() {
 }
 
 void Value::resize(ArrayIndex newSize) {
-  JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
                       "in Json::Value::resize(): requires arrayValue");
-  if (type_ == nullValue)
+  if (type() == nullValue)
     *this = Value(arrayValue);
   ArrayIndex oldSize = size();
   if (newSize == 0)
     clear();
   else if (newSize > oldSize)
-    (*this)[newSize - 1];
+    this->operator[](newSize - 1);
   else {
     for (ArrayIndex index = newSize; index < oldSize; ++index) {
       value_.map_->erase(index);
@@ -1000,12 +923,12 @@ void Value::resize(ArrayIndex newSize) {
 
 Value& Value::operator[](ArrayIndex index) {
   JSON_ASSERT_MESSAGE(
-      type_ == nullValue || type_ == arrayValue,
+      type() == nullValue || type() == arrayValue,
       "in Json::Value::operator[](ArrayIndex): requires arrayValue");
-  if (type_ == nullValue)
+  if (type() == nullValue)
     *this = Value(arrayValue);
   CZString key(index);
-  ObjectValues::iterator it = value_.map_->lower_bound(key);
+  auto it = value_.map_->lower_bound(key);
   if (it != value_.map_->end() && (*it).first == key)
     return (*it).second;
 
@@ -1023,9 +946,9 @@ Value& Value::operator[](int index) {
 
 const Value& Value::operator[](ArrayIndex index) const {
   JSON_ASSERT_MESSAGE(
-      type_ == nullValue || type_ == arrayValue,
+      type() == nullValue || type() == arrayValue,
       "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
-  if (type_ == nullValue)
+  if (type() == nullValue)
     return nullSingleton();
   CZString key(index);
   ObjectValues::const_iterator it = value_.map_->find(key);
@@ -1041,26 +964,85 @@ const Value& Value::operator[](int index) const {
   return (*this)[ArrayIndex(index)];
 }
 
-void Value::initBasic(ValueType vtype, bool allocated) {
-  type_ = vtype;
-  allocated_ = allocated;
-  comments_ = 0;
+void Value::initBasic(ValueType type, bool allocated) {
+  setType(type);
+  setIsAllocated(allocated);
+  comments_ = Comments{};
   start_ = 0;
   limit_ = 0;
 }
 
+void Value::dupPayload(const Value& other) {
+  setType(other.type());
+  setIsAllocated(false);
+  switch (type()) {
+  case nullValue:
+  case intValue:
+  case uintValue:
+  case realValue:
+  case booleanValue:
+    value_ = other.value_;
+    break;
+  case stringValue:
+    if (other.value_.string_ && other.isAllocated()) {
+      unsigned len;
+      char const* str;
+      decodePrefixedString(other.isAllocated(), other.value_.string_, &len,
+                           &str);
+      value_.string_ = duplicateAndPrefixStringValue(str, len);
+      setIsAllocated(true);
+    } else {
+      value_.string_ = other.value_.string_;
+    }
+    break;
+  case arrayValue:
+  case objectValue:
+    value_.map_ = new ObjectValues(*other.value_.map_);
+    break;
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+}
+
+void Value::releasePayload() {
+  switch (type()) {
+  case nullValue:
+  case intValue:
+  case uintValue:
+  case realValue:
+  case booleanValue:
+    break;
+  case stringValue:
+    if (isAllocated())
+      releasePrefixedStringValue(value_.string_);
+    break;
+  case arrayValue:
+  case objectValue:
+    delete value_.map_;
+    break;
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+}
+
+void Value::dupMeta(const Value& other) {
+  comments_ = other.comments_;
+  start_ = other.start_;
+  limit_ = other.limit_;
+}
+
 // Access an object value by name, create a null member if it does not exist.
 // @pre Type of '*this' is object or null.
 // @param key is null-terminated.
 Value& Value::resolveReference(const char* key) {
   JSON_ASSERT_MESSAGE(
-      type_ == nullValue || type_ == objectValue,
+      type() == nullValue || type() == objectValue,
       "in Json::Value::resolveReference(): requires objectValue");
-  if (type_ == nullValue)
+  if (type() == nullValue)
     *this = Value(objectValue);
-  CZString actualKey(
-      key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE!
-  ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
+  CZString actualKey(key, static_cast<unsigned>(strlen(key)),
+                     CZString::noDuplication); // NOTE!
+  auto it = value_.map_->lower_bound(actualKey);
   if (it != value_.map_->end() && (*it).first == actualKey)
     return (*it).second;
 
@@ -1071,16 +1053,15 @@ Value& Value::resolveReference(const char* key) {
 }
 
 // @param key is not null-terminated.
-Value& Value::resolveReference(char const* key, char const* cend)
-{
+Value& Value::resolveReference(char const* key, char const* end) {
   JSON_ASSERT_MESSAGE(
-      type_ == nullValue || type_ == objectValue,
+      type() == nullValue || type() == objectValue,
       "in Json::Value::resolveReference(key, end): requires objectValue");
-  if (type_ == nullValue)
+  if (type() == nullValue)
     *this = Value(objectValue);
-  CZString actualKey(
-      key, static_cast<unsigned>(cend-key), CZString::duplicateOnCopy);
-  ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
+  CZString actualKey(key, static_cast<unsigned>(end - key),
+                     CZString::duplicateOnCopy);
+  auto it = value_.map_->lower_bound(actualKey);
   if (it != value_.map_->end() && (*it).first == actualKey)
     return (*it).second;
 
@@ -1097,27 +1078,35 @@ Value Value::get(ArrayIndex index, const Value& defaultValue) const {
 
 bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
 
-Value const* Value::find(char const* key, char const* cend) const
-{
-  JSON_ASSERT_MESSAGE(
-      type_ == nullValue || type_ == objectValue,
-      "in Json::Value::find(key, end, found): requires objectValue or nullValue");
-  if (type_ == nullValue) return NULL;
-  CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
+Value const* Value::find(char const* begin, char const* end) const {
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
+                      "in Json::Value::find(begin, end): requires "
+                      "objectValue or nullValue");
+  if (type() == nullValue)
+    return nullptr;
+  CZString actualKey(begin, static_cast<unsigned>(end - begin),
+                     CZString::noDuplication);
   ObjectValues::const_iterator it = value_.map_->find(actualKey);
-  if (it == value_.map_->end()) return NULL;
+  if (it == value_.map_->end())
+    return nullptr;
   return &(*it).second;
 }
-const Value& Value::operator[](const char* key) const
-{
+Value* Value::demand(char const* begin, char const* end) {
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
+                      "in Json::Value::demand(begin, end): requires "
+                      "objectValue or nullValue");
+  return &resolveReference(begin, end);
+}
+const Value& Value::operator[](const char* key) const {
   Value const* found = find(key, key + strlen(key));
-  if (!found) return nullSingleton();
+  if (!found)
+    return nullSingleton();
   return *found;
 }
-Value const& Value::operator[](JSONCPP_STRING const& key) const
-{
+Value const& Value::operator[](const String& key) const {
   Value const* found = find(key.data(), key.data() + key.length());
-  if (!found) return nullSingleton();
+  if (!found)
+    return nullSingleton();
   return *found;
 }
 
@@ -1125,7 +1114,7 @@ Value& Value::operator[](const char* key) {
   return resolveReference(key, key + strlen(key));
 }
 
-Value& Value::operator[](const JSONCPP_STRING& key) {
+Value& Value::operator[](const String& key) {
   return resolveReference(key.data(), key.data() + key.length());
 }
 
@@ -1133,179 +1122,140 @@ Value& Value::operator[](const StaticString& key) {
   return resolveReference(key.c_str());
 }
 
-#ifdef JSON_USE_CPPTL
-Value& Value::operator[](const CppTL::ConstString& key) {
-  return resolveReference(key.c_str(), key.end_c_str());
-}
-Value const& Value::operator[](CppTL::ConstString const& key) const
-{
-  Value const* found = find(key.c_str(), key.end_c_str());
-  if (!found) return nullSingleton();
-  return *found;
+Value& Value::append(const Value& value) { return append(Value(value)); }
+
+Value& Value::append(Value&& value) {
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
+                      "in Json::Value::append: requires arrayValue");
+  if (type() == nullValue) {
+    *this = Value(arrayValue);
+  }
+  return this->value_.map_->emplace(size(), std::move(value)).first->second;
 }
-#endif
 
-Value& Value::append(const Value& value) { return (*this)[size()] = value; }
+bool Value::insert(ArrayIndex index, const Value& newValue) {
+  return insert(index, Value(newValue));
+}
 
-#if JSON_HAS_RVALUE_REFERENCES
-  Value& Value::append(Value&& value) { return (*this)[size()] = value; }
-#endif
+bool Value::insert(ArrayIndex index, Value&& newValue) {
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
+                      "in Json::Value::insert: requires arrayValue");
+  ArrayIndex length = size();
+  if (index > length) {
+    return false;
+  }
+  for (ArrayIndex i = length; i > index; i--) {
+    (*this)[i] = std::move((*this)[i - 1]);
+  }
+  (*this)[index] = std::move(newValue);
+  return true;
+}
 
-Value Value::get(char const* key, char const* cend, Value const& defaultValue) const
-{
-  Value const* found = find(key, cend);
+Value Value::get(char const* begin, char const* end,
+                 Value const& defaultValue) const {
+  Value const* found = find(begin, end);
   return !found ? defaultValue : *found;
 }
-Value Value::get(char const* key, Value const& defaultValue) const
-{
+Value Value::get(char const* key, Value const& defaultValue) const {
   return get(key, key + strlen(key), defaultValue);
 }
-Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const
-{
+Value Value::get(String const& key, Value const& defaultValue) const {
   return get(key.data(), key.data() + key.length(), defaultValue);
 }
 
-
-bool Value::removeMember(const char* key, const char* cend, Value* removed)
-{
-  if (type_ != objectValue) {
+bool Value::removeMember(const char* begin, const char* end, Value* removed) {
+  if (type() != objectValue) {
     return false;
   }
-  CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
-  ObjectValues::iterator it = value_.map_->find(actualKey);
+  CZString actualKey(begin, static_cast<unsigned>(end - begin),
+                     CZString::noDuplication);
+  auto it = value_.map_->find(actualKey);
   if (it == value_.map_->end())
     return false;
-  *removed = it->second;
+  if (removed)
+    *removed = std::move(it->second);
   value_.map_->erase(it);
   return true;
 }
-bool Value::removeMember(const char* key, Value* removed)
-{
+bool Value::removeMember(const char* key, Value* removed) {
   return removeMember(key, key + strlen(key), removed);
 }
-bool Value::removeMember(JSONCPP_STRING const& key, Value* removed)
-{
+bool Value::removeMember(String const& key, Value* removed) {
   return removeMember(key.data(), key.data() + key.length(), removed);
 }
-Value Value::removeMember(const char* key)
-{
-  JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
+void Value::removeMember(const char* key) {
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
                       "in Json::Value::removeMember(): requires objectValue");
-  if (type_ == nullValue)
-    return nullSingleton();
+  if (type() == nullValue)
+    return;
 
-  Value removed;  // null
-  removeMember(key, key + strlen(key), &removed);
-  return removed; // still null if removeMember() did nothing
-}
-Value Value::removeMember(const JSONCPP_STRING& key)
-{
-  return removeMember(key.c_str());
+  CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);
+  value_.map_->erase(actualKey);
 }
+void Value::removeMember(const String& key) { removeMember(key.c_str()); }
 
 bool Value::removeIndex(ArrayIndex index, Value* removed) {
-  if (type_ != arrayValue) {
+  if (type() != arrayValue) {
     return false;
   }
   CZString key(index);
-  ObjectValues::iterator it = value_.map_->find(key);
+  auto it = value_.map_->find(key);
   if (it == value_.map_->end()) {
     return false;
   }
-  *removed = it->second;
+  if (removed)
+    *removed = it->second;
   ArrayIndex oldSize = size();
   // shift left all items left, into the place of the "removed"
-  for (ArrayIndex i = index; i < (oldSize - 1); ++i){
+  for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
     CZString keey(i);
     (*value_.map_)[keey] = (*this)[i + 1];
   }
   // erase the last one ("leftover")
   CZString keyLast(oldSize - 1);
-  ObjectValues::iterator itLast = value_.map_->find(keyLast);
+  auto itLast = value_.map_->find(keyLast);
   value_.map_->erase(itLast);
   return true;
 }
 
-#ifdef JSON_USE_CPPTL
-Value Value::get(const CppTL::ConstString& key,
-                 const Value& defaultValue) const {
-  return get(key.c_str(), key.end_c_str(), defaultValue);
+bool Value::isMember(char const* begin, char const* end) const {
+  Value const* value = find(begin, end);
+  return nullptr != value;
 }
-#endif
-
-bool Value::isMember(char const* key, char const* cend) const
-{
-  Value const* value = find(key, cend);
-  return NULL != value;
-}
-bool Value::isMember(char const* key) const
-{
+bool Value::isMember(char const* key) const {
   return isMember(key, key + strlen(key));
 }
-bool Value::isMember(JSONCPP_STRING const& key) const
-{
+bool Value::isMember(String const& key) const {
   return isMember(key.data(), key.data() + key.length());
 }
 
-#ifdef JSON_USE_CPPTL
-bool Value::isMember(const CppTL::ConstString& key) const {
-  return isMember(key.c_str(), key.end_c_str());
-}
-#endif
-
 Value::Members Value::getMemberNames() const {
   JSON_ASSERT_MESSAGE(
-      type_ == nullValue || type_ == objectValue,
+      type() == nullValue || type() == objectValue,
       "in Json::Value::getMemberNames(), value must be objectValue");
-  if (type_ == nullValue)
+  if (type() == nullValue)
     return Value::Members();
   Members members;
   members.reserve(value_.map_->size());
   ObjectValues::const_iterator it = value_.map_->begin();
   ObjectValues::const_iterator itEnd = value_.map_->end();
   for (; it != itEnd; ++it) {
-    members.push_back(JSONCPP_STRING((*it).first.data(),
-                                  (*it).first.length()));
+    members.push_back(String((*it).first.data(), (*it).first.length()));
   }
   return members;
 }
-//
-//# ifdef JSON_USE_CPPTL
-// EnumMemberNames
-// Value::enumMemberNames() const
-//{
-//   if ( type_ == objectValue )
-//   {
-//      return CppTL::Enum::any(  CppTL::Enum::transform(
-//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
-//         MemberNamesTransform() ) );
-//   }
-//   return EnumMemberNames();
-//}
-//
-//
-// EnumValues
-// Value::enumValues() const
-//{
-//   if ( type_ == objectValue  ||  type_ == arrayValue )
-//      return CppTL::Enum::anyValues( *(value_.map_),
-//                                     CppTL::Type<const Value &>() );
-//   return EnumValues();
-//}
-//
-//# endif
 
 static bool IsIntegral(double d) {
   double integral_part;
   return modf(d, &integral_part) == 0.0;
 }
 
-bool Value::isNull() const { return type_ == nullValue; }
+bool Value::isNull() const { return type() == nullValue; }
 
-bool Value::isBool() const { return type_ == booleanValue; }
+bool Value::isBool() const { return type() == booleanValue; }
 
 bool Value::isInt() const {
-  switch (type_) {
+  switch (type()) {
   case intValue:
 #if defined(JSON_HAS_INT64)
     return value_.int_ >= minInt && value_.int_ <= maxInt;
@@ -1324,7 +1274,7 @@ bool Value::isInt() const {
 }
 
 bool Value::isUInt() const {
-  switch (type_) {
+  switch (type()) {
   case intValue:
 #if defined(JSON_HAS_INT64)
     return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
@@ -1348,7 +1298,7 @@ bool Value::isUInt() const {
 
 bool Value::isInt64() const {
 #if defined(JSON_HAS_INT64)
-  switch (type_) {
+  switch (type()) {
   case intValue:
     return true;
   case uintValue:
@@ -1368,7 +1318,7 @@ bool Value::isInt64() const {
 
 bool Value::isUInt64() const {
 #if defined(JSON_HAS_INT64)
-  switch (type_) {
+  switch (type()) {
   case intValue:
     return value_.int_ >= 0;
   case uintValue:
@@ -1387,61 +1337,92 @@ bool Value::isUInt64() const {
 }
 
 bool Value::isIntegral() const {
-  switch (type_) {
-    case intValue:
-    case uintValue:
-      return true;
-    case realValue:
+  switch (type()) {
+  case intValue:
+  case uintValue:
+    return true;
+  case realValue:
 #if defined(JSON_HAS_INT64)
-      // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
-      // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
-      // require the value to be strictly less than the limit.
-      return value_.real_ >= double(minInt64) && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
+    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
+    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
+    // require the value to be strictly less than the limit.
+    return value_.real_ >= double(minInt64) &&
+           value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
 #else
-      return value_.real_ >= minInt && value_.real_ <= maxUInt && IsIntegral(value_.real_);
+    return value_.real_ >= minInt && value_.real_ <= maxUInt &&
+           IsIntegral(value_.real_);
 #endif // JSON_HAS_INT64
-    default:
-      break;
+  default:
+    break;
   }
   return false;
 }
 
-bool Value::isDouble() const { return type_ == intValue || type_ == uintValue || type_ == realValue; }
+bool Value::isDouble() const {
+  return type() == intValue || type() == uintValue || type() == realValue;
+}
 
 bool Value::isNumeric() const { return isDouble(); }
 
-bool Value::isString() const { return type_ == stringValue; }
+bool Value::isString() const { return type() == stringValue; }
 
-bool Value::isArray() const { return type_ == arrayValue; }
+bool Value::isArray() const { return type() == arrayValue; }
 
-bool Value::isObject() const { return type_ == objectValue; }
+bool Value::isObject() const { return type() == objectValue; }
 
-void Value::setComment(const char* comment, size_t len, CommentPlacement placement) {
-  if (!comments_)
-    comments_ = new CommentInfo[numberOfCommentPlacement];
-  if ((len > 0) && (comment[len-1] == '\n')) {
-    // Always discard trailing newline, to aid indentation.
-    len -= 1;
-  }
-  comments_[placement].setComment(comment, len);
+Value::Comments::Comments(const Comments& that)
+    : ptr_{cloneUnique(that.ptr_)} {}
+
+Value::Comments::Comments(Comments&& that) : ptr_{std::move(that.ptr_)} {}
+
+Value::Comments& Value::Comments::operator=(const Comments& that) {
+  ptr_ = cloneUnique(that.ptr_);
+  return *this;
 }
 
-void Value::setComment(const char* comment, CommentPlacement placement) {
-  setComment(comment, strlen(comment), placement);
+Value::Comments& Value::Comments::operator=(Comments&& that) {
+  ptr_ = std::move(that.ptr_);
+  return *this;
+}
+
+bool Value::Comments::has(CommentPlacement slot) const {
+  return ptr_ && !(*ptr_)[slot].empty();
 }
 
-void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) {
-  setComment(comment.c_str(), comment.length(), placement);
+String Value::Comments::get(CommentPlacement slot) const {
+  if (!ptr_)
+    return {};
+  return (*ptr_)[slot];
+}
+
+void Value::Comments::set(CommentPlacement slot, String comment) {
+  if (!ptr_) {
+    ptr_ = std::unique_ptr<Array>(new Array());
+  }
+  // check comments array boundry.
+  if (slot < CommentPlacement::numberOfCommentPlacement) {
+    (*ptr_)[slot] = std::move(comment);
+  }
+}
+
+void Value::setComment(String comment, CommentPlacement placement) {
+  if (!comment.empty() && (comment.back() == '\n')) {
+    // Always discard trailing newline, to aid indentation.
+    comment.pop_back();
+  }
+  JSON_ASSERT(!comment.empty());
+  JSON_ASSERT_MESSAGE(
+      comment[0] == '\0' || comment[0] == '/',
+      "in Json::Value::setComment(): Comments must start with /");
+  comments_.set(placement, std::move(comment));
 }
 
 bool Value::hasComment(CommentPlacement placement) const {
-  return comments_ != 0 && comments_[placement].comment_ != 0;
+  return comments_.has(placement);
 }
 
-JSONCPP_STRING Value::getComment(CommentPlacement placement) const {
-  if (hasComment(placement))
-    return comments_[placement].comment_;
-  return "";
+String Value::getComment(CommentPlacement placement) const {
+  return comments_.get(placement);
 }
 
 void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
@@ -1452,18 +1433,18 @@ ptrdiff_t Value::getOffsetStart() const { return start_; }
 
 ptrdiff_t Value::getOffsetLimit() const { return limit_; }
 
-JSONCPP_STRING Value::toStyledString() const {
+String Value::toStyledString() const {
   StreamWriterBuilder builder;
 
-  JSONCPP_STRING out = this->hasComment(commentBefore) ? "\n" : "";
+  String out = this->hasComment(commentBefore) ? "\n" : "";
   out += Json::writeString(builder, *this);
-  out += "\n";
+  out += '\n';
 
   return out;
 }
 
 Value::const_iterator Value::begin() const {
-  switch (type_) {
+  switch (type()) {
   case arrayValue:
   case objectValue:
     if (value_.map_)
@@ -1472,11 +1453,11 @@ Value::const_iterator Value::begin() const {
   default:
     break;
   }
-  return const_iterator();
+  return {};
 }
 
 Value::const_iterator Value::end() const {
-  switch (type_) {
+  switch (type()) {
   case arrayValue:
   case objectValue:
     if (value_.map_)
@@ -1485,11 +1466,11 @@ Value::const_iterator Value::end() const {
   default:
     break;
   }
-  return const_iterator();
+  return {};
 }
 
 Value::iterator Value::begin() {
-  switch (type_) {
+  switch (type()) {
   case arrayValue:
   case objectValue:
     if (value_.map_)
@@ -1502,7 +1483,7 @@ Value::iterator Value::begin() {
 }
 
 Value::iterator Value::end() {
-  switch (type_) {
+  switch (type()) {
   case arrayValue:
   case objectValue:
     if (value_.map_)
@@ -1517,25 +1498,20 @@ Value::iterator Value::end() {
 // class PathArgument
 // //////////////////////////////////////////////////////////////////
 
-PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {}
+PathArgument::PathArgument() = default;
 
 PathArgument::PathArgument(ArrayIndex index)
-    : key_(), index_(index), kind_(kindIndex) {}
+    : index_(index), kind_(kindIndex) {}
 
-PathArgument::PathArgument(const char* key)
-    : key_(key), index_(), kind_(kindKey) {}
+PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {}
 
-PathArgument::PathArgument(const JSONCPP_STRING& key)
-    : key_(key.c_str()), index_(), kind_(kindKey) {}
+PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {}
 
 // class Path
 // //////////////////////////////////////////////////////////////////
 
-Path::Path(const JSONCPP_STRING& path,
-           const PathArgument& a1,
-           const PathArgument& a2,
-           const PathArgument& a3,
-           const PathArgument& a4,
+Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2,
+           const PathArgument& a3, const PathArgument& a4,
            const PathArgument& a5) {
   InArgs in;
   in.reserve(5);
@@ -1547,10 +1523,10 @@ Path::Path(const JSONCPP_STRING& path,
   makePath(path, in);
 }
 
-void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) {
+void Path::makePath(const String& path, const InArgs& in) {
   const char* current = path.c_str();
   const char* end = current + path.length();
-  InArgs::const_iterator itInArg = in.begin();
+  auto itInArg = in.begin();
   while (current != end) {
     if (*current == '[') {
       ++current;
@@ -1573,13 +1549,12 @@ void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) {
       const char* beginName = current;
       while (current != end && !strchr("[.", *current))
         ++current;
-      args_.push_back(JSONCPP_STRING(beginName, current));
+      args_.push_back(String(beginName, current));
     }
   }
 }
 
-void Path::addPathInArg(const JSONCPP_STRING& /*path*/,
-                        const InArgs& in,
+void Path::addPathInArg(const String& /*path*/, const InArgs& in,
                         InArgs::const_iterator& itInArg,
                         PathArgument::Kind kind) {
   if (itInArg == in.end()) {
@@ -1591,30 +1566,29 @@ void Path::addPathInArg(const JSONCPP_STRING& /*path*/,
   }
 }
 
-void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) {
+void Path::invalidPath(const String& /*path*/, int /*location*/) {
   // Error: invalid path.
 }
 
 const Value& Path::resolve(const Value& root) const {
   const Value* node = &root;
-  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
-    const PathArgument& arg = *it;
+  for (const auto& arg : args_) {
     if (arg.kind_ == PathArgument::kindIndex) {
       if (!node->isArray() || !node->isValidIndex(arg.index_)) {
-        // Error: unable to resolve path (array value expected at position...
-        return Value::null;
+        // Error: unable to resolve path (array value expected at position... )
+        return Value::nullSingleton();
       }
       node = &((*node)[arg.index_]);
     } else if (arg.kind_ == PathArgument::kindKey) {
       if (!node->isObject()) {
         // Error: unable to resolve path (object value expected at position...)
-        return Value::null;
+        return Value::nullSingleton();
       }
       node = &((*node)[arg.key_]);
       if (node == &Value::nullSingleton()) {
         // Error: unable to resolve path (object has no member named '' at
         // position...)
-        return Value::null;
+        return Value::nullSingleton();
       }
     }
   }
@@ -1623,8 +1597,7 @@ const Value& Path::resolve(const Value& root) const {
 
 Value Path::resolve(const Value& root, const Value& defaultValue) const {
   const Value* node = &root;
-  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
-    const PathArgument& arg = *it;
+  for (const auto& arg : args_) {
     if (arg.kind_ == PathArgument::kindIndex) {
       if (!node->isArray() || !node->isValidIndex(arg.index_))
         return defaultValue;
@@ -1642,8 +1615,7 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const {
 
 Value& Path::make(Value& root) const {
   Value* node = &root;
-  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
-    const PathArgument& arg = *it;
+  for (const auto& arg : args_) {
     if (arg.kind_ == PathArgument::kindIndex) {
       if (!node->isArray()) {
         // Error: node is not an array at position ...
index 5243bfe..d6128b8 100644 (file)
@@ -15,31 +15,21 @@ namespace Json {
 // //////////////////////////////////////////////////////////////////
 // //////////////////////////////////////////////////////////////////
 
-ValueIteratorBase::ValueIteratorBase()
-    : current_(), isNull_(true) {
-}
+ValueIteratorBase::ValueIteratorBase() : current_() {}
 
 ValueIteratorBase::ValueIteratorBase(
     const Value::ObjectValues::iterator& current)
     : current_(current), isNull_(false) {}
 
-Value& ValueIteratorBase::deref() const {
-  return current_->second;
-}
+Value& ValueIteratorBase::deref() { return current_->second; }
+const Value& ValueIteratorBase::deref() const { return current_->second; }
 
-void ValueIteratorBase::increment() {
-  ++current_;
-}
+void ValueIteratorBase::increment() { ++current_; }
 
-void ValueIteratorBase::decrement() {
-  --current_;
-}
+void ValueIteratorBase::decrement() { --current_; }
 
 ValueIteratorBase::difference_type
 ValueIteratorBase::computeDistance(const SelfType& other) const {
-#ifdef JSON_USE_CPPTL_SMALLMAP
-  return other.current_ - current_;
-#else
   // Iterator for null value are initialized using the default
   // constructor, which initialize current_ to the default
   // std::map::iterator. As begin() and end() are two instance
@@ -60,7 +50,6 @@ ValueIteratorBase::computeDistance(const SelfType& other) const {
     ++myDistance;
   }
   return myDistance;
-#endif
 }
 
 bool ValueIteratorBase::isEqual(const SelfType& other) const {
@@ -92,12 +81,13 @@ UInt ValueIteratorBase::index() const {
   return Value::UInt(-1);
 }
 
-JSONCPP_STRING ValueIteratorBase::name() const {
+String ValueIteratorBase::name() const {
   char const* keey;
   char const* end;
   keey = memberName(&end);
-  if (!keey) return JSONCPP_STRING();
-  return JSONCPP_STRING(keey, end);
+  if (!keey)
+    return String();
+  return String(keey, end);
 }
 
 char const* ValueIteratorBase::memberName() const {
@@ -108,8 +98,8 @@ char const* ValueIteratorBase::memberName() const {
 char const* ValueIteratorBase::memberName(char const** end) const {
   const char* cname = (*current_).first.data();
   if (!cname) {
-    *end = NULL;
-    return NULL;
+    *end = nullptr;
+    return nullptr;
   }
   *end = cname + (*current_).first.length();
   return cname;
@@ -123,7 +113,7 @@ char const* ValueIteratorBase::memberName(char const** end) const {
 // //////////////////////////////////////////////////////////////////
 // //////////////////////////////////////////////////////////////////
 
-ValueConstIterator::ValueConstIterator() {}
+ValueConstIterator::ValueConstIterator() = default;
 
 ValueConstIterator::ValueConstIterator(
     const Value::ObjectValues::iterator& current)
@@ -146,7 +136,7 @@ operator=(const ValueIteratorBase& other) {
 // //////////////////////////////////////////////////////////////////
 // //////////////////////////////////////////////////////////////////
 
-ValueIterator::ValueIterator() {}
+ValueIterator::ValueIterator() = default;
 
 ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
     : ValueIteratorBase(current) {}
@@ -156,8 +146,7 @@ ValueIterator::ValueIterator(const ValueConstIterator& other)
   throwRuntimeError("ConstIterator to Iterator should never be allowed.");
 }
 
-ValueIterator::ValueIterator(const ValueIterator& other)
-    : ValueIteratorBase(other) {}
+ValueIterator::ValueIterator(const ValueIterator& other) = default;
 
 ValueIterator& ValueIterator::operator=(const SelfType& other) {
   copy(other);
index fc86505..8bf02db 100644 (file)
 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
 
 #if !defined(JSON_IS_AMALGAMATION)
-#include <json/writer.h>
 #include "json_tool.h"
+#include <json/writer.h>
 #endif // if !defined(JSON_IS_AMALGAMATION)
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cstring>
 #include <iomanip>
 #include <memory>
+#include <set>
 #include <sstream>
 #include <utility>
-#include <set>
-#include <cassert>
-#include <cstring>
+
+#if __cplusplus >= 201103L
+#include <cmath>
 #include <cstdio>
 
-#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
-#include <float.h>
-#define isfinite _finite
-#elif defined(__sun) && defined(__SVR4) //Solaris
-#if !defined(isfinite)
-#include <ieeefp.h>
-#define isfinite finite
+#if !defined(isnan)
+#define isnan std::isnan
 #endif
-#elif defined(_AIX)
+
 #if !defined(isfinite)
-#include <math.h>
-#define isfinite finite
-#endif
-#elif defined(__hpux)
-#if !defined(isfinite) && !defined(__GNUC__)
-#if defined(__ia64) && !defined(finite)
-#define isfinite(x) ((sizeof(x) == sizeof(float) ? \
-                     _Isfinitef(x) : _IsFinite(x)))
-#else
-#include <math.h>
-#define isfinite finite
-#endif
+#define isfinite std::isfinite
 #endif
+
 #else
 #include <cmath>
-#if !(defined(__QNXNTO__)) // QNX already defines isfinite
-#define isfinite std::isfinite
-#endif
-#endif
+#include <cstdio>
 
 #if defined(_MSC_VER)
-#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
-#define snprintf sprintf_s
-#elif _MSC_VER >= 1900 // VC++ 14.0 and above
-#define snprintf std::snprintf
-#else
-#define snprintf _snprintf
-#endif
-#elif defined(__ANDROID__) || defined(__QNXNTO__)
-#define snprintf snprintf
-#elif __cplusplus >= 201103L
-#if !defined(__MINGW32__) && !defined(__CYGWIN__)
-#define snprintf std::snprintf
-#endif
+#if !defined(isnan)
+#include <float.h>
+#define isnan _isnan
 #endif
 
-#if defined(__BORLANDC__)  
+#if !defined(isfinite)
 #include <float.h>
 #define isfinite _finite
-#define snprintf _snprintf
 #endif
 
-// Solaris
-#if defined(__sun)
-# include <ieeefp.h>
-# if !defined(isfinite)
-#  define isfinite finite
-# endif
-#endif
+#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
+#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
+#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
+
+#endif //_MSC_VER
 
-// AIX
-#if defined(_AIX)
-# if !defined(isfinite)
-#  define isfinite finite
-# endif
+#if defined(__sun) && defined(__SVR4) // Solaris
+#if !defined(isfinite)
+#include <ieeefp.h>
+#define isfinite finite
+#endif
 #endif
 
-// HP-UX
 #if defined(__hpux)
-# if !defined(isfinite)
-#  if defined(__ia64) && !defined(finite) && !defined(__GNUC__)
-#   define isfinite(x) ((sizeof(x) == sizeof(float) ? \
-                        _Isfinitef(x) : _Isfinite(x)))
-#  else
-#   include <math.h>
-#   define isfinite finite
-#  endif
-# endif
+#if !defined(isfinite)
+#if defined(__ia64) && !defined(finite)
+#define isfinite(x)                                                            \
+  ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x)))
+#endif
+#endif
+#endif
+
+#if !defined(isnan)
+// IEEE standard states that NaN values will not compare to themselves
+#define isnan(x) (x != x)
 #endif
 
-// Ancient glibc
-#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 2
-# if !defined(isfinite)
-#  define isfinite __finite
-# endif
+#if !defined(__APPLE__)
+#if !defined(isfinite)
+#define isfinite finite
+#endif
+#endif
 #endif
 
-#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
+#if defined(_MSC_VER)
 // Disable warning about strdup being deprecated.
 #pragma warning(disable : 4996)
 #endif
 namespace Json {
 
 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
-typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
+using StreamWriterPtr = std::unique_ptr<StreamWriter>;
 #else
-typedef std::auto_ptr<StreamWriter>   StreamWriterPtr;
+using StreamWriterPtr = std::auto_ptr<StreamWriter>;
 #endif
 
-static bool containsControlCharacter(const char* str) {
-  while (*str) {
-    if (isControlCharacter(*(str++)))
-      return true;
-  }
-  return false;
-}
-
-static bool containsControlCharacter0(const char* str, unsigned len) {
-  char const* end = str + len;
-  while (end != str) {
-    if (isControlCharacter(*str) || 0==*str)
-      return true;
-    ++str;
-  }
-  return false;
-}
-
-JSONCPP_STRING valueToString(LargestInt value) {
+String valueToString(LargestInt value) {
   UIntToStringBuffer buffer;
   char* current = buffer + sizeof(buffer);
   if (value == Value::minLargestInt) {
@@ -150,7 +107,7 @@ JSONCPP_STRING valueToString(LargestInt value) {
   return current;
 }
 
-JSONCPP_STRING valueToString(LargestUInt value) {
+String valueToString(LargestUInt value) {
   UIntToStringBuffer buffer;
   char* current = buffer + sizeof(buffer);
   uintToString(value, current);
@@ -160,147 +117,171 @@ JSONCPP_STRING valueToString(LargestUInt value) {
 
 #if defined(JSON_HAS_INT64)
 
-JSONCPP_STRING valueToString(Int value) {
-  return valueToString(LargestInt(value));
-}
+String valueToString(Int value) { return valueToString(LargestInt(value)); }
 
-JSONCPP_STRING valueToString(UInt value) {
-  return valueToString(LargestUInt(value));
-}
+String valueToString(UInt value) { return valueToString(LargestUInt(value)); }
 
 #endif // # if defined(JSON_HAS_INT64)
 
 namespace {
-JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) {
-  // Allocate a buffer that is more than large enough to store the 16 digits of
-  // precision requested below.
-  char buffer[36];
-  int len = -1;
-
-  char formatString[15];
-  snprintf(formatString, sizeof(formatString), "%%.%dg", precision);
-
+String valueToString(double value, bool useSpecialFloats,
+                     unsigned int precision, PrecisionType precisionType) {
   // Print into the buffer. We need not request the alternative representation
-  // that always has a decimal point because JSON doesn't distingish the
+  // that always has a decimal point because JSON doesn't distinguish the
   // concepts of reals and integers.
-  if (isfinite(value)) {
-    len = snprintf(buffer, sizeof(buffer), formatString, value);
-    fixNumericLocale(buffer, buffer + len);
+  if (!isfinite(value)) {
+    static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"},
+                                           {"null", "-1e+9999", "1e+9999"}};
+    return reps[useSpecialFloats ? 0 : 1]
+               [isnan(value) ? 0 : (value < 0) ? 1 : 2];
+  }
 
-    // try to ensure we preserve the fact that this was given to us as a double on input
-    if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {
-      strcat(buffer, ".0");
+  String buffer(size_t(36), '\0');
+  while (true) {
+    int len = jsoncpp_snprintf(
+        &*buffer.begin(), buffer.size(),
+        (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f",
+        precision, value);
+    assert(len >= 0);
+    auto wouldPrint = static_cast<size_t>(len);
+    if (wouldPrint >= buffer.size()) {
+      buffer.resize(wouldPrint + 1);
+      continue;
     }
+    buffer.resize(wouldPrint);
+    break;
+  }
 
-  } else {
-    // IEEE standard states that NaN values will not compare to themselves
-    if (value != value) {
-      len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
-    } else if (value < 0) {
-      len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
-    } else {
-      len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
-    }
+  buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
+
+  // strip the zero padding from the right
+  if (precisionType == PrecisionType::decimalPlaces) {
+    buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end());
+  }
+
+  // try to ensure we preserve the fact that this was given to us as a double on
+  // input
+  if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
+    buffer += ".0";
   }
-  assert(len >= 0);
   return buffer;
 }
+} // namespace
+
+String valueToString(double value, unsigned int precision,
+                     PrecisionType precisionType) {
+  return valueToString(value, false, precision, precisionType);
 }
 
-JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); }
+String valueToString(bool value) { return value ? "true" : "false"; }
 
-JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }
+static bool doesAnyCharRequireEscaping(char const* s, size_t n) {
+  assert(s || !n);
 
-JSONCPP_STRING valueToQuotedString(const char* value) {
-  if (value == NULL)
-    return "";
-  // Not sure how to handle unicode...
-  if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL &&
-      !containsControlCharacter(value))
-    return JSONCPP_STRING("\"") + value + "\"";
-  // We have to walk value and escape any special characters.
-  // Appending to JSONCPP_STRING is not efficient, but this should be rare.
-  // (Note: forward slashes are *not* rare, but I am not escaping them.)
-  JSONCPP_STRING::size_type maxsize =
-      strlen(value) * 2 + 3; // allescaped+quotes+NULL
-  JSONCPP_STRING result;
-  result.reserve(maxsize); // to avoid lots of mallocs
-  result += "\"";
-  for (const char* c = value; *c != 0; ++c) {
-    switch (*c) {
-    case '\"':
-      result += "\\\"";
-      break;
-    case '\\':
-      result += "\\\\";
-      break;
-    case '\b':
-      result += "\\b";
-      break;
-    case '\f':
-      result += "\\f";
-      break;
-    case '\n':
-      result += "\\n";
-      break;
-    case '\r':
-      result += "\\r";
-      break;
-    case '\t':
-      result += "\\t";
-      break;
-    // case '/':
-    // Even though \/ is considered a legal escape in JSON, a bare
-    // slash is also legal, so I see no reason to escape it.
-    // (I hope I am not misunderstanding something.
-    // blep notes: actually escaping \/ may be useful in javascript to avoid </
-    // sequence.
-    // Should add a flag to allow this compatibility mode and prevent this
-    // sequence from occurring.
-    default:
-      if (isControlCharacter(*c)) {
-        JSONCPP_OSTRINGSTREAM oss;
-        oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
-            << std::setw(4) << static_cast<int>(*c);
-        result += oss.str();
-      } else {
-        result += *c;
-      }
-      break;
-    }
+  return std::any_of(s, s + n, [](unsigned char c) {
+    return c == '\\' || c == '"' || c < 0x20 || c > 0x7F;
+  });
+}
+
+static unsigned int utf8ToCodepoint(const char*& s, const char* e) {
+  const unsigned int REPLACEMENT_CHARACTER = 0xFFFD;
+
+  unsigned int firstByte = static_cast<unsigned char>(*s);
+
+  if (firstByte < 0x80)
+    return firstByte;
+
+  if (firstByte < 0xE0) {
+    if (e - s < 2)
+      return REPLACEMENT_CHARACTER;
+
+    unsigned int calculated =
+        ((firstByte & 0x1F) << 6) | (static_cast<unsigned int>(s[1]) & 0x3F);
+    s += 1;
+    // oversized encoded characters are invalid
+    return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated;
   }
-  result += "\"";
+
+  if (firstByte < 0xF0) {
+    if (e - s < 3)
+      return REPLACEMENT_CHARACTER;
+
+    unsigned int calculated = ((firstByte & 0x0F) << 12) |
+                              ((static_cast<unsigned int>(s[1]) & 0x3F) << 6) |
+                              (static_cast<unsigned int>(s[2]) & 0x3F);
+    s += 2;
+    // surrogates aren't valid codepoints itself
+    // shouldn't be UTF-8 encoded
+    if (calculated >= 0xD800 && calculated <= 0xDFFF)
+      return REPLACEMENT_CHARACTER;
+    // oversized encoded characters are invalid
+    return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated;
+  }
+
+  if (firstByte < 0xF8) {
+    if (e - s < 4)
+      return REPLACEMENT_CHARACTER;
+
+    unsigned int calculated = ((firstByte & 0x07) << 18) |
+                              ((static_cast<unsigned int>(s[1]) & 0x3F) << 12) |
+                              ((static_cast<unsigned int>(s[2]) & 0x3F) << 6) |
+                              (static_cast<unsigned int>(s[3]) & 0x3F);
+    s += 3;
+    // oversized encoded characters are invalid
+    return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated;
+  }
+
+  return REPLACEMENT_CHARACTER;
+}
+
+static const char hex2[] = "000102030405060708090a0b0c0d0e0f"
+                           "101112131415161718191a1b1c1d1e1f"
+                           "202122232425262728292a2b2c2d2e2f"
+                           "303132333435363738393a3b3c3d3e3f"
+                           "404142434445464748494a4b4c4d4e4f"
+                           "505152535455565758595a5b5c5d5e5f"
+                           "606162636465666768696a6b6c6d6e6f"
+                           "707172737475767778797a7b7c7d7e7f"
+                           "808182838485868788898a8b8c8d8e8f"
+                           "909192939495969798999a9b9c9d9e9f"
+                           "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+                           "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+                           "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+                           "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+                           "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+                           "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
+
+static String toHex16Bit(unsigned int x) {
+  const unsigned int hi = (x >> 8) & 0xff;
+  const unsigned int lo = x & 0xff;
+  String result(4, ' ');
+  result[0] = hex2[2 * hi];
+  result[1] = hex2[2 * hi + 1];
+  result[2] = hex2[2 * lo];
+  result[3] = hex2[2 * lo + 1];
   return result;
 }
 
-// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp
-static char const* strnpbrk(char const* s, char const* accept, size_t n) {
-  assert((s || !n) && accept);
+static void appendRaw(String& result, unsigned ch) {
+  result += static_cast<char>(ch);
+}
 
-  char const* const end = s + n;
-  for (char const* cur = s; cur < end; ++cur) {
-    int const c = *cur;
-    for (char const* a = accept; *a; ++a) {
-      if (*a == c) {
-        return cur;
-      }
-    }
-  }
-  return NULL;
+static void appendHex(String& result, unsigned ch) {
+  result.append("\\u").append(toHex16Bit(ch));
 }
-static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) {
-  if (value == NULL)
+
+static String valueToQuotedStringN(const char* value, unsigned length,
+                                   bool emitUTF8 = false) {
+  if (value == nullptr)
     return "";
-  // Not sure how to handle unicode...
-  if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL &&
-      !containsControlCharacter0(value, length))
-    return JSONCPP_STRING("\"") + value + "\"";
+
+  if (!doesAnyCharRequireEscaping(value, length))
+    return String("\"") + value + "\"";
   // We have to walk value and escape any special characters.
-  // Appending to JSONCPP_STRING is not efficient, but this should be rare.
+  // Appending to String is not efficient, but this should be rare.
   // (Note: forward slashes are *not* rare, but I am not escaping them.)
-  JSONCPP_STRING::size_type maxsize =
-      length * 2 + 3; // allescaped+quotes+NULL
-  JSONCPP_STRING result;
+  String::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL
+  String result;
   result.reserve(maxsize); // to avoid lots of mallocs
   result += "\"";
   char const* end = value + length;
@@ -335,44 +316,63 @@ static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) {
     // sequence.
     // Should add a flag to allow this compatibility mode and prevent this
     // sequence from occurring.
-    default:
-      if ((isControlCharacter(*c)) || (*c == 0)) {
-        JSONCPP_OSTRINGSTREAM oss;
-        oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
-            << std::setw(4) << static_cast<int>(*c);
-        result += oss.str();
+    default: {
+      if (emitUTF8) {
+        unsigned codepoint = static_cast<unsigned char>(*c);
+        if (codepoint < 0x20) {
+          appendHex(result, codepoint);
+        } else {
+          appendRaw(result, codepoint);
+        }
       } else {
-        result += *c;
+        unsigned codepoint = utf8ToCodepoint(c, end); // modifies `c`
+        if (codepoint < 0x20) {
+          appendHex(result, codepoint);
+        } else if (codepoint < 0x80) {
+          appendRaw(result, codepoint);
+        } else if (codepoint < 0x10000) {
+          // Basic Multilingual Plane
+          appendHex(result, codepoint);
+        } else {
+          // Extended Unicode. Encode 20 bits as a surrogate pair.
+          codepoint -= 0x10000;
+          appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff));
+          appendHex(result, 0xdc00 + (codepoint & 0x3ff));
+        }
       }
-      break;
+    } break;
     }
   }
   result += "\"";
   return result;
 }
 
+String valueToQuotedString(const char* value) {
+  return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
+}
+
 // Class Writer
 // //////////////////////////////////////////////////////////////////
-Writer::~Writer() {}
+Writer::~Writer() = default;
 
 // Class FastWriter
 // //////////////////////////////////////////////////////////////////
 
 FastWriter::FastWriter()
-    : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
-      omitEndingLineFeed_(false) {}
 
-void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
+    = default;
+
+void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }
 
 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
 
 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
 
-JSONCPP_STRING FastWriter::write(const Value& root) {
+String FastWriter::write(const Value& root) {
   document_.clear();
   writeValue(root);
   if (!omitEndingLineFeed_)
-    document_ += "\n";
+    document_ += '\n';
   return document_;
 }
 
@@ -391,13 +391,13 @@ void FastWriter::writeValue(const Value& value) {
   case realValue:
     document_ += valueToString(value.asDouble());
     break;
-  case stringValue:
-  {
+  case stringValue: {
     // Is NULL possible for value.string_? No.
     char const* str;
     char const* end;
     bool ok = value.getString(&str, &end);
-    if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));
+    if (ok)
+      document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
     break;
   }
   case booleanValue:
@@ -416,13 +416,13 @@ void FastWriter::writeValue(const Value& value) {
   case objectValue: {
     Value::Members members(value.getMemberNames());
     document_ += '{';
-    for (Value::Members::iterator it = members.begin(); it != members.end();
-         ++it) {
-      const JSONCPP_STRING& name = *it;
+    for (auto it = members.begin(); it != members.end(); ++it) {
+      const String& name = *it;
       if (it != members.begin())
         document_ += ',';
-      document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
-      document_ += yamlCompatiblityEnabled_ ? ": " : ":";
+      document_ += valueToQuotedStringN(name.data(),
+                                        static_cast<unsigned>(name.length()));
+      document_ += yamlCompatibilityEnabled_ ? ": " : ":";
       writeValue(value[name]);
     }
     document_ += '}';
@@ -433,17 +433,16 @@ void FastWriter::writeValue(const Value& value) {
 // Class StyledWriter
 // //////////////////////////////////////////////////////////////////
 
-StyledWriter::StyledWriter()
-    : rightMargin_(74), indentSize_(3), addChildValues_() {}
+StyledWriter::StyledWriter() = default;
 
-JSONCPP_STRING StyledWriter::write(const Value& root) {
+String StyledWriter::write(const Value& root) {
   document_.clear();
   addChildValues_ = false;
   indentString_.clear();
   writeCommentBeforeValue(root);
   writeValue(root);
   writeCommentAfterValueOnSameLine(root);
-  document_ += "\n";
+  document_ += '\n';
   return document_;
 }
 
@@ -461,14 +460,15 @@ void StyledWriter::writeValue(const Value& value) {
   case realValue:
     pushValue(valueToString(value.asDouble()));
     break;
-  case stringValue:
-  {
+  case stringValue: {
     // Is NULL possible for value.string_? No.
     char const* str;
     char const* end;
     bool ok = value.getString(&str, &end);
-    if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
-    else pushValue("");
+    if (ok)
+      pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
+    else
+      pushValue("");
     break;
   }
   case booleanValue:
@@ -484,9 +484,9 @@ void StyledWriter::writeValue(const Value& value) {
     else {
       writeWithIndent("{");
       indent();
-      Value::Members::iterator it = members.begin();
+      auto it = members.begin();
       for (;;) {
-        const JSONCPP_STRING& name = *it;
+        const String& name = *it;
         const Value& childValue = value[name];
         writeCommentBeforeValue(childValue);
         writeWithIndent(valueToQuotedString(name.c_str()));
@@ -511,7 +511,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
   if (size == 0)
     pushValue("[]");
   else {
-    bool isArrayMultiLine = isMultineArray(value);
+    bool isArrayMultiLine = isMultilineArray(value);
     if (isArrayMultiLine) {
       writeWithIndent("[");
       indent();
@@ -549,14 +549,14 @@ void StyledWriter::writeArrayValue(const Value& value) {
   }
 }
 
-bool StyledWriter::isMultineArray(const Value& value) {
+bool StyledWriter::isMultilineArray(const Value& value) {
   ArrayIndex const size = value.size();
   bool isMultiLine = size * 3 >= rightMargin_;
   childValues_.clear();
   for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
     const Value& childValue = value[index];
     isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
-                        childValue.size() > 0);
+                   !childValue.empty());
   }
   if (!isMultiLine) // check if line length > max line length
   {
@@ -576,7 +576,7 @@ bool StyledWriter::isMultineArray(const Value& value) {
   return isMultiLine;
 }
 
-void StyledWriter::pushValue(const JSONCPP_STRING& value) {
+void StyledWriter::pushValue(const String& value) {
   if (addChildValues_)
     childValues_.push_back(value);
   else
@@ -594,12 +594,12 @@ void StyledWriter::writeIndent() {
   document_ += indentString_;
 }
 
-void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) {
+void StyledWriter::writeWithIndent(const String& value) {
   writeIndent();
   document_ += value;
 }
 
-void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); }
+void StyledWriter::indent() { indentString_ += String(indentSize_, ' '); }
 
 void StyledWriter::unindent() {
   assert(indentString_.size() >= indentSize_);
@@ -610,20 +610,19 @@ void StyledWriter::writeCommentBeforeValue(const Value& root) {
   if (!root.hasComment(commentBefore))
     return;
 
-  document_ += "\n";
+  document_ += '\n';
   writeIndent();
-  const JSONCPP_STRING& comment = root.getComment(commentBefore);
-  JSONCPP_STRING::const_iterator iter = comment.begin();
+  const String& comment = root.getComment(commentBefore);
+  String::const_iterator iter = comment.begin();
   while (iter != comment.end()) {
     document_ += *iter;
-    if (*iter == '\n' &&
-       (iter != comment.end() && *(iter + 1) == '/'))
+    if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
       writeIndent();
     ++iter;
   }
 
   // Comments are stripped of trailing newlines, so add one here
-  document_ += "\n";
+  document_ += '\n';
 }
 
 void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
@@ -631,9 +630,9 @@ void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
     document_ += " " + root.getComment(commentAfterOnSameLine);
 
   if (root.hasComment(commentAfter)) {
-    document_ += "\n";
+    document_ += '\n';
     document_ += root.getComment(commentAfter);
-    document_ += "\n";
+    document_ += '\n';
   }
 }
 
@@ -646,22 +645,23 @@ bool StyledWriter::hasCommentForValue(const Value& value) {
 // Class StyledStreamWriter
 // //////////////////////////////////////////////////////////////////
 
-StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation)
-    : document_(NULL), rightMargin_(74), indentation_(indentation),
-      addChildValues_() {}
+StyledStreamWriter::StyledStreamWriter(String indentation)
+    : document_(nullptr), indentation_(std::move(indentation)),
+      addChildValues_(), indented_(false) {}
 
-void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) {
+void StyledStreamWriter::write(OStream& out, const Value& root) {
   document_ = &out;
   addChildValues_ = false;
   indentString_.clear();
   indented_ = true;
   writeCommentBeforeValue(root);
-  if (!indented_) writeIndent();
+  if (!indented_)
+    writeIndent();
   indented_ = true;
   writeValue(root);
   writeCommentAfterValueOnSameLine(root);
   *document_ << "\n";
-  document_ = NULL; // Forget the stream, for safety.
+  document_ = nullptr; // Forget the stream, for safety.
 }
 
 void StyledStreamWriter::writeValue(const Value& value) {
@@ -678,14 +678,15 @@ void StyledStreamWriter::writeValue(const Value& value) {
   case realValue:
     pushValue(valueToString(value.asDouble()));
     break;
-  case stringValue:
-  {
+  case stringValue: {
     // Is NULL possible for value.string_? No.
     char const* str;
     char const* end;
     bool ok = value.getString(&str, &end);
-    if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
-    else pushValue("");
+    if (ok)
+      pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
+    else
+      pushValue("");
     break;
   }
   case booleanValue:
@@ -701,9 +702,9 @@ void StyledStreamWriter::writeValue(const Value& value) {
     else {
       writeWithIndent("{");
       indent();
-      Value::Members::iterator it = members.begin();
+      auto it = members.begin();
       for (;;) {
-        const JSONCPP_STRING& name = *it;
+        const String& name = *it;
         const Value& childValue = value[name];
         writeCommentBeforeValue(childValue);
         writeWithIndent(valueToQuotedString(name.c_str()));
@@ -728,7 +729,7 @@ void StyledStreamWriter::writeArrayValue(const Value& value) {
   if (size == 0)
     pushValue("[]");
   else {
-    bool isArrayMultiLine = isMultineArray(value);
+    bool isArrayMultiLine = isMultilineArray(value);
     if (isArrayMultiLine) {
       writeWithIndent("[");
       indent();
@@ -740,7 +741,8 @@ void StyledStreamWriter::writeArrayValue(const Value& value) {
         if (hasChildValue)
           writeWithIndent(childValues_[index]);
         else {
-          if (!indented_) writeIndent();
+          if (!indented_)
+            writeIndent();
           indented_ = true;
           writeValue(childValue);
           indented_ = false;
@@ -768,14 +770,14 @@ void StyledStreamWriter::writeArrayValue(const Value& value) {
   }
 }
 
-bool StyledStreamWriter::isMultineArray(const Value& value) {
+bool StyledStreamWriter::isMultilineArray(const Value& value) {
   ArrayIndex const size = value.size();
   bool isMultiLine = size * 3 >= rightMargin_;
   childValues_.clear();
   for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
     const Value& childValue = value[index];
     isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
-                        childValue.size() > 0);
+                   !childValue.empty());
   }
   if (!isMultiLine) // check if line length > max line length
   {
@@ -795,7 +797,7 @@ bool StyledStreamWriter::isMultineArray(const Value& value) {
   return isMultiLine;
 }
 
-void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) {
+void StyledStreamWriter::pushValue(const String& value) {
   if (addChildValues_)
     childValues_.push_back(value);
   else
@@ -810,8 +812,9 @@ void StyledStreamWriter::writeIndent() {
   *document_ << '\n' << indentString_;
 }
 
-void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) {
-  if (!indented_) writeIndent();
+void StyledStreamWriter::writeWithIndent(const String& value) {
+  if (!indented_)
+    writeIndent();
   *document_ << value;
   indented_ = false;
 }
@@ -827,13 +830,13 @@ void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
   if (!root.hasComment(commentBefore))
     return;
 
-  if (!indented_) writeIndent();
-  const JSONCPP_STRING& comment = root.getComment(commentBefore);
-  JSONCPP_STRING::const_iterator iter = comment.begin();
+  if (!indented_)
+    writeIndent();
+  const String& comment = root.getComment(commentBefore);
+  String::const_iterator iter = comment.begin();
   while (iter != comment.end()) {
     *document_ << *iter;
-    if (*iter == '\n' &&
-       (iter != comment.end() && *(iter + 1) == '/'))
+    if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
       // writeIndent();  // would include newline
       *document_ << indentString_;
     ++iter;
@@ -865,84 +868,73 @@ bool StyledStreamWriter::hasCommentForValue(const Value& value) {
 struct CommentStyle {
   /// Decide whether to write comments.
   enum Enum {
-    None,  ///< Drop all comments.
-    Most,  ///< Recover odd behavior of previous versions (not implemented yet).
-    All  ///< Keep all comments.
+    None, ///< Drop all comments.
+    Most, ///< Recover odd behavior of previous versions (not implemented yet).
+    All   ///< Keep all comments.
   };
 };
 
-struct BuiltStyledStreamWriter : public StreamWriter
-{
-  BuiltStyledStreamWriter(
-      JSONCPP_STRING const& indentation,
-      CommentStyle::Enum cs,
-      JSONCPP_STRING const& colonSymbol,
-      JSONCPP_STRING const& nullSymbol,
-      JSONCPP_STRING const& endingLineFeedSymbol,
-      bool useSpecialFloats,
-      unsigned int precision);
-  int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;
+struct BuiltStyledStreamWriter : public StreamWriter {
+  BuiltStyledStreamWriter(String indentation, CommentStyle::Enum cs,
+                          String colonSymbol, String nullSymbol,
+                          String endingLineFeedSymbol, bool useSpecialFloats,
+                          bool emitUTF8, unsigned int precision,
+                          PrecisionType precisionType);
+  int write(Value const& root, OStream* sout) override;
+
 private:
   void writeValue(Value const& value);
   void writeArrayValue(Value const& value);
-  bool isMultineArray(Value const& value);
-  void pushValue(JSONCPP_STRING const& value);
+  bool isMultilineArray(Value const& value);
+  void pushValue(String const& value);
   void writeIndent();
-  void writeWithIndent(JSONCPP_STRING const& value);
+  void writeWithIndent(String const& value);
   void indent();
   void unindent();
   void writeCommentBeforeValue(Value const& root);
   void writeCommentAfterValueOnSameLine(Value const& root);
   static bool hasCommentForValue(const Value& value);
 
-  typedef std::vector<JSONCPP_STRING> ChildValues;
+  using ChildValues = std::vector<String>;
 
   ChildValues childValues_;
-  JSONCPP_STRING indentString_;
+  String indentString_;
   unsigned int rightMargin_;
-  JSONCPP_STRING indentation_;
+  String indentation_;
   CommentStyle::Enum cs_;
-  JSONCPP_STRING colonSymbol_;
-  JSONCPP_STRING nullSymbol_;
-  JSONCPP_STRING endingLineFeedSymbol_;
+  String colonSymbol_;
+  String nullSymbol_;
+  String endingLineFeedSymbol_;
   bool addChildValues_ : 1;
   bool indented_ : 1;
   bool useSpecialFloats_ : 1;
+  bool emitUTF8_ : 1;
   unsigned int precision_;
+  PrecisionType precisionType_;
 };
 BuiltStyledStreamWriter::BuiltStyledStreamWriter(
-      JSONCPP_STRING const& indentation,
-      CommentStyle::Enum cs,
-      JSONCPP_STRING const& colonSymbol,
-      JSONCPP_STRING const& nullSymbol,
-      JSONCPP_STRING const& endingLineFeedSymbol,
-      bool useSpecialFloats,
-      unsigned int precision)
-  : rightMargin_(74)
-  , indentation_(indentation)
-  , cs_(cs)
-  , colonSymbol_(colonSymbol)
-  , nullSymbol_(nullSymbol)
-  , endingLineFeedSymbol_(endingLineFeedSymbol)
-  , addChildValues_(false)
-  , indented_(false)
-  , useSpecialFloats_(useSpecialFloats)
-  , precision_(precision)
-{
-}
-int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout)
-{
+    String indentation, CommentStyle::Enum cs, String colonSymbol,
+    String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats,
+    bool emitUTF8, unsigned int precision, PrecisionType precisionType)
+    : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs),
+      colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)),
+      endingLineFeedSymbol_(std::move(endingLineFeedSymbol)),
+      addChildValues_(false), indented_(false),
+      useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8),
+      precision_(precision), precisionType_(precisionType) {}
+int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) {
   sout_ = sout;
   addChildValues_ = false;
   indented_ = true;
   indentString_.clear();
   writeCommentBeforeValue(root);
-  if (!indented_) writeIndent();
+  if (!indented_)
+    writeIndent();
   indented_ = true;
   writeValue(root);
   writeCommentAfterValueOnSameLine(root);
   *sout_ << endingLineFeedSymbol_;
-  sout_ = NULL;
+  sout_ = nullptr;
   return 0;
 }
 void BuiltStyledStreamWriter::writeValue(Value const& value) {
@@ -957,16 +949,19 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
     pushValue(valueToString(value.asLargestUInt()));
     break;
   case realValue:
-    pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
+    pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_,
+                            precisionType_));
     break;
-  case stringValue:
-  {
+  case stringValue: {
     // Is NULL is possible for value.string_? No.
     char const* str;
     char const* end;
     bool ok = value.getString(&str, &end);
-    if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
-    else pushValue("");
+    if (ok)
+      pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str),
+                                     emitUTF8_));
+    else
+      pushValue("");
     break;
   }
   case booleanValue:
@@ -982,12 +977,13 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
     else {
       writeWithIndent("{");
       indent();
-      Value::Members::iterator it = members.begin();
+      auto it = members.begin();
       for (;;) {
-        JSONCPP_STRING const& name = *it;
+        String const& name = *it;
         Value const& childValue = value[name];
         writeCommentBeforeValue(childValue);
-        writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
+        writeWithIndent(valueToQuotedStringN(
+            name.data(), static_cast<unsigned>(name.length()), emitUTF8_));
         *sout_ << colonSymbol_;
         writeValue(childValue);
         if (++it == members.end()) {
@@ -1009,7 +1005,7 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
   if (size == 0)
     pushValue("[]");
   else {
-    bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
+    bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value);
     if (isMultiLine) {
       writeWithIndent("[");
       indent();
@@ -1021,7 +1017,8 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
         if (hasChildValue)
           writeWithIndent(childValues_[index]);
         else {
-          if (!indented_) writeIndent();
+          if (!indented_)
+            writeIndent();
           indented_ = true;
           writeValue(childValue);
           indented_ = false;
@@ -1039,26 +1036,28 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
     {
       assert(childValues_.size() == size);
       *sout_ << "[";
-      if (!indentation_.empty()) *sout_ << " ";
+      if (!indentation_.empty())
+        *sout_ << " ";
       for (unsigned index = 0; index < size; ++index) {
         if (index > 0)
           *sout_ << ((!indentation_.empty()) ? ", " : ",");
         *sout_ << childValues_[index];
       }
-      if (!indentation_.empty()) *sout_ << " ";
+      if (!indentation_.empty())
+        *sout_ << " ";
       *sout_ << "]";
     }
   }
 }
 
-bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
+bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) {
   ArrayIndex const size = value.size();
   bool isMultiLine = size * 3 >= rightMargin_;
   childValues_.clear();
   for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
     Value const& childValue = value[index];
     isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
-                        childValue.size() > 0);
+                   !childValue.empty());
   }
   if (!isMultiLine) // check if line length > max line length
   {
@@ -1078,7 +1077,7 @@ bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
   return isMultiLine;
 }
 
-void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) {
+void BuiltStyledStreamWriter::pushValue(String const& value) {
   if (addChildValues_)
     childValues_.push_back(value);
   else
@@ -1097,8 +1096,9 @@ void BuiltStyledStreamWriter::writeIndent() {
   }
 }
 
-void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) {
-  if (!indented_) writeIndent();
+void BuiltStyledStreamWriter::writeWithIndent(String const& value) {
+  if (!indented_)
+    writeIndent();
   *sout_ << value;
   indented_ = false;
 }
@@ -1111,17 +1111,18 @@ void BuiltStyledStreamWriter::unindent() {
 }
 
 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
-  if (cs_ == CommentStyle::None) return;
+  if (cs_ == CommentStyle::None)
+    return;
   if (!root.hasComment(commentBefore))
     return;
 
-  if (!indented_) writeIndent();
-  const JSONCPP_STRING& comment = root.getComment(commentBefore);
-  JSONCPP_STRING::const_iterator iter = comment.begin();
+  if (!indented_)
+    writeIndent();
+  const String& comment = root.getComment(commentBefore);
+  String::const_iterator iter = comment.begin();
   while (iter != comment.end()) {
     *sout_ << *iter;
-    if (*iter == '\n' &&
-       (iter != comment.end() && *(iter + 1) == '/'))
+    if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
       // writeIndent();  // would write extra newline
       *sout_ << indentString_;
     ++iter;
@@ -1129,8 +1130,10 @@ void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
   indented_ = false;
 }
 
-void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
-  if (cs_ == CommentStyle::None) return;
+void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(
+    Value const& root) {
+  if (cs_ == CommentStyle::None)
+    return;
   if (root.hasComment(commentAfterOnSameLine))
     *sout_ << " " + root.getComment(commentAfterOnSameLine);
 
@@ -1150,28 +1153,19 @@ bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
 ///////////////
 // StreamWriter
 
-StreamWriter::StreamWriter()
-    : sout_(NULL)
-{
-}
-StreamWriter::~StreamWriter()
-{
-}
-StreamWriter::Factory::~Factory()
-{}
-StreamWriterBuilder::StreamWriterBuilder()
-{
-  setDefaults(&settings_);
-}
-StreamWriterBuilder::~StreamWriterBuilder()
-{}
-StreamWriter* StreamWriterBuilder::newStreamWriter() const
-{
-  JSONCPP_STRING indentation = settings_["indentation"].asString();
-  JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
-  bool eyc = settings_["enableYAMLCompatibility"].asBool();
-  bool dnp = settings_["dropNullPlaceholders"].asBool();
-  bool usf = settings_["useSpecialFloats"].asBool(); 
+StreamWriter::StreamWriter() : sout_(nullptr) {}
+StreamWriter::~StreamWriter() = default;
+StreamWriter::Factory::~Factory() = default;
+StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); }
+StreamWriterBuilder::~StreamWriterBuilder() = default;
+StreamWriter* StreamWriterBuilder::newStreamWriter() const {
+  const String indentation = settings_["indentation"].asString();
+  const String cs_str = settings_["commentStyle"].asString();
+  const String pt_str = settings_["precisionType"].asString();
+  const bool eyc = settings_["enableYAMLCompatibility"].asBool();
+  const bool dnp = settings_["dropNullPlaceholders"].asBool();
+  const bool usf = settings_["useSpecialFloats"].asBool();
+  const bool emitUTF8 = settings_["emitUTF8"].asBool();
   unsigned int pre = settings_["precision"].asUInt();
   CommentStyle::Enum cs = CommentStyle::All;
   if (cs_str == "All") {
@@ -1181,74 +1175,80 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
   } else {
     throwRuntimeError("commentStyle must be 'All' or 'None'");
   }
-  JSONCPP_STRING colonSymbol = " : ";
+  PrecisionType precisionType(significantDigits);
+  if (pt_str == "significant") {
+    precisionType = PrecisionType::significantDigits;
+  } else if (pt_str == "decimal") {
+    precisionType = PrecisionType::decimalPlaces;
+  } else {
+    throwRuntimeError("precisionType must be 'significant' or 'decimal'");
+  }
+  String colonSymbol = " : ";
   if (eyc) {
     colonSymbol = ": ";
   } else if (indentation.empty()) {
     colonSymbol = ":";
   }
-  JSONCPP_STRING nullSymbol = "null";
+  String nullSymbol = "null";
   if (dnp) {
     nullSymbol.clear();
   }
-  if (pre > 17) pre = 17;
-  JSONCPP_STRING endingLineFeedSymbol;
-  return new BuiltStyledStreamWriter(
-      indentation, cs,
-      colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
+  if (pre > 17)
+    pre = 17;
+  String endingLineFeedSymbol;
+  return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol,
+                                     endingLineFeedSymbol, usf, emitUTF8, pre,
+                                     precisionType);
 }
-static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
-{
-  valid_keys->clear();
-  valid_keys->insert("indentation");
-  valid_keys->insert("commentStyle");
-  valid_keys->insert("enableYAMLCompatibility");
-  valid_keys->insert("dropNullPlaceholders");
-  valid_keys->insert("useSpecialFloats");
-  valid_keys->insert("precision");
-}
-bool StreamWriterBuilder::validate(Json::Value* invalid) const
-{
-  Json::Value my_invalid;
-  if (!invalid) invalid = &my_invalid;  // so we do not need to test for NULL
-  Json::Value& inv = *invalid;
-  std::set<JSONCPP_STRING> valid_keys;
-  getValidWriterKeys(&valid_keys);
-  Value::Members keys = settings_.getMemberNames();
-  size_t n = keys.size();
-  for (size_t i = 0; i < n; ++i) {
-    JSONCPP_STRING const& key = keys[i];
-    if (valid_keys.find(key) == valid_keys.end()) {
-      inv[key] = settings_[key];
-    }
+
+bool StreamWriterBuilder::validate(Json::Value* invalid) const {
+  static const auto& valid_keys = *new std::set<String>{
+      "indentation",
+      "commentStyle",
+      "enableYAMLCompatibility",
+      "dropNullPlaceholders",
+      "useSpecialFloats",
+      "emitUTF8",
+      "precision",
+      "precisionType",
+  };
+  for (auto si = settings_.begin(); si != settings_.end(); ++si) {
+    auto key = si.name();
+    if (valid_keys.count(key))
+      continue;
+    if (invalid)
+      (*invalid)[std::move(key)] = *si;
+    else
+      return false;
   }
-  return 0u == inv.size();
+  return invalid ? invalid->empty() : true;
 }
-Value& StreamWriterBuilder::operator[](JSONCPP_STRING key)
-{
+
+Value& StreamWriterBuilder::operator[](const String& key) {
   return settings_[key];
 }
 // static
-void StreamWriterBuilder::setDefaults(Json::Value* settings)
-{
+void StreamWriterBuilder::setDefaults(Json::Value* settings) {
   //! [StreamWriterBuilderDefaults]
   (*settings)["commentStyle"] = "All";
   (*settings)["indentation"] = "\t";
   (*settings)["enableYAMLCompatibility"] = false;
   (*settings)["dropNullPlaceholders"] = false;
   (*settings)["useSpecialFloats"] = false;
+  (*settings)["emitUTF8"] = false;
   (*settings)["precision"] = 17;
+  (*settings)["precisionType"] = "significant";
   //! [StreamWriterBuilderDefaults]
 }
 
-JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) {
-  JSONCPP_OSTRINGSTREAM sout;
-  StreamWriterPtr const writer(builder.newStreamWriter());
+String writeString(StreamWriter::Factory const& factory, Value const& root) {
+  OStringStream sout;
+  StreamWriterPtr const writer(factory.newStreamWriter());
   writer->write(root, &sout);
   return sout.str();
 }
 
-JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {
+OStream& operator<<(OStream& sout, Value const& root) {
   StreamWriterBuilder builder;
   StreamWriterPtr const writer(builder.newStreamWriter());
   writer->write(root, &sout);
index 79452ff..ba65470 100644 (file)
@@ -171,32 +171,32 @@ IF (MSVC)
   # This is added into CMAKE_C_FLAGS when CMAKE_BUILD_TYPE is "Debug"
   # Enable level 4 C4062: The enumerate has no associated handler in a switch
   #                       statement and there is no default that can catch it.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4062")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14062")
   # Enable level 4 C4254: A larger bit field was assigned to a smaller bit
   #                       field.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4254")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14254")
   # Enable level 4 C4295: An array was initialized but the last character in
   #                       the array is not a null; accessing the array may
   #                       produce unexpected results.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4295")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14295")
   # Enable level 4 C4296: An unsigned variable was used in a comparison
   #                       operation with zero.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4296")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14296")
   # Enable level 4 C4389: An operation involved signed and unsigned variables.
   #                       This could result in a loss of data.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4389")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14389")
   # Enable level 4 C4505: The given function is local and not referenced in
   #                       the body of the module; therefore, the function is
   #                       dead code.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4505")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14505")
   # Enable level 4 C4514: The optimizer removed an inline function that is not
   #                       called.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4514")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14514")
   # Enable level 4 C4702: Unreachable code.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4702")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14702")
   # Enable level 4 C4706: The test value in a conditional expression was the
   #                       result of an assignment.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4706")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14706")
   # /Oi option enables built-in functions.
   SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Oi")
   #################################################################
@@ -1404,6 +1404,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(strchr HAVE_STRCHR)
 CHECK_FUNCTION_EXISTS_GLIBC(strdup HAVE_STRDUP)
 CHECK_FUNCTION_EXISTS_GLIBC(strerror HAVE_STRERROR)
 CHECK_FUNCTION_EXISTS_GLIBC(strncpy_s HAVE_STRNCPY_S)
+CHECK_FUNCTION_EXISTS_GLIBC(strnlen HAVE_STRNLEN)
 CHECK_FUNCTION_EXISTS_GLIBC(strrchr HAVE_STRRCHR)
 CHECK_FUNCTION_EXISTS_GLIBC(symlink HAVE_SYMLINK)
 CHECK_FUNCTION_EXISTS_GLIBC(timegm HAVE_TIMEGM)
@@ -1475,15 +1476,19 @@ CHECK_C_SOURCE_COMPILES(
   "#include <sys/sysmacros.h>\nint main() { return major(256); }"
   MAJOR_IN_SYSMACROS)
 
+IF(ENABLE_LZMA)
 CMAKE_PUSH_CHECK_STATE()
 SET(CMAKE_REQUIRED_LIBRARIES ${LIBLZMA_LIBRARIES})
 SET(CMAKE_REQUIRED_INCLUDES ${LIBLZMA_INCLUDE_DIR})
 
 CHECK_C_SOURCE_COMPILES(
   "#include <lzma.h>\n#if LZMA_VERSION < 50020000\n#error unsupported\n#endif\nint main(void){lzma_stream_encoder_mt(0, 0); return 0;}"
-HAVE_LZMA_STREAM_ENCODER_MT)
+  HAVE_LZMA_STREAM_ENCODER_MT)
 
 CMAKE_POP_CHECK_STATE()
+ELSE()
+  SET(HAVE_LZMA_STREAM_ENCODER_MT 0)
+ENDIF(ENABLE_LZMA)
 
 IF(HAVE_STRERROR_R)
   SET(HAVE_DECL_STRERROR_R 1)
@@ -2007,6 +2012,11 @@ IF(MSVC)
   ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
 ENDIF(MSVC)
 
+IF(APPLE)
+  # CC_MD5_Init() functions are deprecated on macOS 10.15, but we want to use them
+  ADD_DEFINITIONS(-Wno-deprecated-declarations)
+ENDIF(APPLE)
+
 IF(0) # CMake does not build libarchive's tests.
 IF(ENABLE_TEST)
   ADD_CUSTOM_TARGET(run_all_tests)
index 14bbefa..1b97235 100644 (file)
@@ -15,7 +15,6 @@ the actual statements in the files are controlling.
 * The following source files are also subject in whole or in part to
   a 3-clause UC Regents copyright; please read the individual source
   files for details:
-   libarchive/archive_entry.c
    libarchive/archive_read_support_filter_compress.c
    libarchive/archive_write_add_filter_compress.c
    libarchive/mtree.5
index fc8529a..bc5a43f 100644 (file)
@@ -24,10 +24,10 @@ ENDFOREACH()
 #       thus there's a good chance it'll make some binutils versions unhappy...
 #       This only affects Libs.private (looked up for static builds) though.
 CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc.in
-               ${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc
+               ${CMAKE_CURRENT_BINARY_DIR}/build/pkgconfig/libarchive.pc
                @ONLY)
 # And install it, of course ;).
 IF(ENABLE_INSTALL)
-  INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc
+  INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/build/pkgconfig/libarchive.pc
           DESTINATION "lib/pkgconfig")
 ENDIF()
index f38601f..9bd2667 100644 (file)
@@ -1,4 +1,5 @@
 /* config.h.  Generated from build/cmake/config.h.in by cmake configure */
+#define __LIBARCHIVE_CONFIG_H_INCLUDED 1
 #if defined(__osf__)
 # define _OSF_SOURCE
 #endif
 /* Define to 1 if you have the `strchr' function. */
 #cmakedefine HAVE_STRCHR 1
 
+/* Define to 1 if you have the `strnlen' function. */
+#cmakedefine HAVE_STRNLEN 1
+
 /* Define to 1 if you have the `strdup' function. */
 #cmakedefine HAVE_STRDUP 1
 
index 574e087..a1f0b87 100644 (file)
@@ -36,7 +36,7 @@
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
-#define        ARCHIVE_VERSION_NUMBER 3004002
+#define        ARCHIVE_VERSION_NUMBER 3005001
 
 #include <sys/stat.h>
 #include <stddef.h>  /* for wchar_t */
@@ -152,7 +152,7 @@ __LA_DECL int               archive_version_number(void);
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define        ARCHIVE_VERSION_ONLY_STRING "3.4.2"
+#define        ARCHIVE_VERSION_ONLY_STRING "3.5.1"
 #define        ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char * archive_version_string(void);
 
@@ -243,6 +243,8 @@ typedef int archive_open_callback(struct archive *, void *_client_data);
 
 typedef int    archive_close_callback(struct archive *, void *_client_data);
 
+typedef int    archive_free_callback(struct archive *, void *_client_data);
+
 /* Switches from one client data object to the next/prev client data object.
  * This is useful for reading from different data blocks such as a set of files
  * that make up one large file.
@@ -415,6 +417,7 @@ __LA_DECL int archive_read_support_compression_xz(struct archive *)
 #endif
 
 __LA_DECL int archive_read_support_filter_all(struct archive *);
+__LA_DECL int archive_read_support_filter_by_code(struct archive *, int);
 __LA_DECL int archive_read_support_filter_bzip2(struct archive *);
 __LA_DECL int archive_read_support_filter_compress(struct archive *);
 __LA_DECL int archive_read_support_filter_gzip(struct archive *);
@@ -814,9 +817,13 @@ __LA_DECL int archive_write_set_format_filter_by_ext(struct archive *a, const ch
 __LA_DECL int archive_write_set_format_filter_by_ext_def(struct archive *a, const char *filename, const char * def_ext);
 __LA_DECL int archive_write_zip_set_compression_deflate(struct archive *);
 __LA_DECL int archive_write_zip_set_compression_store(struct archive *);
+/* Deprecated; use archive_write_open2 instead */
 __LA_DECL int archive_write_open(struct archive *, void *,
                     archive_open_callback *, archive_write_callback *,
                     archive_close_callback *);
+__LA_DECL int archive_write_open2(struct archive *, void *,
+                    archive_open_callback *, archive_write_callback *,
+                    archive_close_callback *, archive_free_callback *);
 __LA_DECL int archive_write_open_fd(struct archive *, int _fd);
 __LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
 __LA_DECL int archive_write_open_filename_w(struct archive *,
index 952e20d..ead7e36 100644 (file)
@@ -595,7 +595,7 @@ archive_acl_text_len(struct archive_acl *acl, int want_type, int flags,
                                else
                                        length += sizeof(uid_t) * 3 + 1;
                        } else {
-                               r = archive_mstring_get_mbs_l(&ap->name, &name,
+                               r = archive_mstring_get_mbs_l(a, &ap->name, &name,
                                    &len, sc);
                                if (r != 0)
                                        return (0);
@@ -968,7 +968,7 @@ archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
                else
                        prefix = NULL;
                r = archive_mstring_get_mbs_l(
-                   &ap->name, &name, &len, sc);
+                   NULL, &ap->name, &name, &len, sc);
                if (r != 0) {
                        free(s);
                        return (NULL);
@@ -1402,14 +1402,14 @@ isint_w(const wchar_t *start, const wchar_t *end, int *result)
        if (start >= end)
                return (0);
        while (start < end) {
-               if (*start < '0' || *start > '9')
+               if (*start < L'0' || *start > L'9')
                        return (0);
                if (n > (INT_MAX / 10) ||
-                   (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) {
+                   (n == INT_MAX / 10 && (*start - L'0') > INT_MAX % 10)) {
                        n = INT_MAX;
                } else {
                        n *= 10;
-                       n += *start - '0';
+                       n += *start - L'0';
                }
                start++;
        }
index 288ce23..1f40072 100644 (file)
@@ -54,7 +54,7 @@ errmsg(const char *m)
        ssize_t written;
 
        while (s > 0) {
-               written = write(2, m, strlen(m));
+               written = write(2, m, s);
                if (written <= 0)
                        return;
                m += written;
index 8ab2b09..d4bca90 100644 (file)
@@ -347,8 +347,31 @@ aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
 static int
 aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)
 {
+#if NETTLE_VERSION_MAJOR < 3
        aes_set_encrypt_key(&ctx->ctx, ctx->key_len, ctx->key);
        aes_encrypt(&ctx->ctx, AES_BLOCK_SIZE, ctx->encr_buf, ctx->nonce);
+#else
+       switch(ctx->key_len) {
+       case AES128_KEY_SIZE:
+               aes128_set_encrypt_key(&ctx->ctx.c128, ctx->key);
+               aes128_encrypt(&ctx->ctx.c128, AES_BLOCK_SIZE, ctx->encr_buf,
+                   ctx->nonce);
+               break;
+       case AES192_KEY_SIZE:
+               aes192_set_encrypt_key(&ctx->ctx.c192, ctx->key);
+               aes192_encrypt(&ctx->ctx.c192, AES_BLOCK_SIZE, ctx->encr_buf,
+                   ctx->nonce);
+               break;
+       case AES256_KEY_SIZE:
+               aes256_set_encrypt_key(&ctx->ctx.c256, ctx->key);
+               aes256_encrypt(&ctx->ctx.c256, AES_BLOCK_SIZE, ctx->encr_buf,
+                   ctx->nonce);
+               break;
+       default:
+               return -1;
+               break;
+       }
+#endif
        return 0;
 }
 
index 64a2055..16b6d16 100644 (file)
@@ -104,9 +104,18 @@ typedef struct {
 #include <nettle/pbkdf2.h>
 #endif
 #include <nettle/aes.h>
+#include <nettle/version.h>
 
 typedef struct {
+#if NETTLE_VERSION_MAJOR < 3
        struct aes_ctx  ctx;
+#else
+       union {
+               struct aes128_ctx c128;
+               struct aes192_ctx c192;
+               struct aes256_ctx c256;
+       }               ctx;
+#endif
        uint8_t         key[AES_MAX_KEY_SIZE];
        unsigned        key_len;
        uint8_t         nonce[AES_BLOCK_SIZE];
index 34c58ac..410df01 100644 (file)
@@ -109,14 +109,14 @@ win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
 #if defined(ARCHIVE_CRYPTO_MD5_LIBC)
 
 static int
-__archive_libc_md5init(archive_md5_ctx *ctx)
+__archive_md5init(archive_md5_ctx *ctx)
 {
   MD5Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libc_md5update(archive_md5_ctx *ctx, const void *indata,
+__archive_md5update(archive_md5_ctx *ctx, const void *indata,
     size_t insize)
 {
   MD5Update(ctx, indata, insize);
@@ -124,7 +124,7 @@ __archive_libc_md5update(archive_md5_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libc_md5final(archive_md5_ctx *ctx, void *md)
+__archive_md5final(archive_md5_ctx *ctx, void *md)
 {
   MD5Final(md, ctx);
   return (ARCHIVE_OK);
@@ -133,14 +133,14 @@ __archive_libc_md5final(archive_md5_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
 
 static int
-__archive_libmd_md5init(archive_md5_ctx *ctx)
+__archive_md5init(archive_md5_ctx *ctx)
 {
   MD5Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libmd_md5update(archive_md5_ctx *ctx, const void *indata,
+__archive_md5update(archive_md5_ctx *ctx, const void *indata,
     size_t insize)
 {
   MD5Update(ctx, indata, insize);
@@ -148,7 +148,7 @@ __archive_libmd_md5update(archive_md5_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libmd_md5final(archive_md5_ctx *ctx, void *md)
+__archive_md5final(archive_md5_ctx *ctx, void *md)
 {
   MD5Final(md, ctx);
   return (ARCHIVE_OK);
@@ -157,14 +157,14 @@ __archive_libmd_md5final(archive_md5_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
 
 static int
-__archive_libsystem_md5init(archive_md5_ctx *ctx)
+__archive_md5init(archive_md5_ctx *ctx)
 {
   CC_MD5_Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libsystem_md5update(archive_md5_ctx *ctx, const void *indata,
+__archive_md5update(archive_md5_ctx *ctx, const void *indata,
     size_t insize)
 {
   CC_MD5_Update(ctx, indata, insize);
@@ -172,7 +172,7 @@ __archive_libsystem_md5update(archive_md5_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libsystem_md5final(archive_md5_ctx *ctx, void *md)
+__archive_md5final(archive_md5_ctx *ctx, void *md)
 {
   CC_MD5_Final(md, ctx);
   return (ARCHIVE_OK);
@@ -181,7 +181,7 @@ __archive_libsystem_md5final(archive_md5_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_MD5_MBEDTLS)
 
 static int
-__archive_mbedtls_md5init(archive_md5_ctx *ctx)
+__archive_md5init(archive_md5_ctx *ctx)
 {
   mbedtls_md5_init(ctx);
   if (mbedtls_md5_starts_ret(ctx) == 0)
@@ -191,7 +191,7 @@ __archive_mbedtls_md5init(archive_md5_ctx *ctx)
 }
 
 static int
-__archive_mbedtls_md5update(archive_md5_ctx *ctx, const void *indata,
+__archive_md5update(archive_md5_ctx *ctx, const void *indata,
     size_t insize)
 {
   if (mbedtls_md5_update_ret(ctx, indata, insize) == 0)
@@ -201,7 +201,7 @@ __archive_mbedtls_md5update(archive_md5_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_mbedtls_md5final(archive_md5_ctx *ctx, void *md)
+__archive_md5final(archive_md5_ctx *ctx, void *md)
 {
   if (mbedtls_md5_finish_ret(ctx, md) == 0) {
     mbedtls_md5_free(ctx);
@@ -215,14 +215,14 @@ __archive_mbedtls_md5final(archive_md5_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
 
 static int
-__archive_nettle_md5init(archive_md5_ctx *ctx)
+__archive_md5init(archive_md5_ctx *ctx)
 {
   md5_init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_nettle_md5update(archive_md5_ctx *ctx, const void *indata,
+__archive_md5update(archive_md5_ctx *ctx, const void *indata,
     size_t insize)
 {
   md5_update(ctx, insize, indata);
@@ -230,7 +230,7 @@ __archive_nettle_md5update(archive_md5_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_nettle_md5final(archive_md5_ctx *ctx, void *md)
+__archive_md5final(archive_md5_ctx *ctx, void *md)
 {
   md5_digest(ctx, MD5_DIGEST_SIZE, md);
   return (ARCHIVE_OK);
@@ -239,7 +239,7 @@ __archive_nettle_md5final(archive_md5_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
 
 static int
-__archive_openssl_md5init(archive_md5_ctx *ctx)
+__archive_md5init(archive_md5_ctx *ctx)
 {
   if ((*ctx = EVP_MD_CTX_new()) == NULL)
        return (ARCHIVE_FAILED);
@@ -248,7 +248,7 @@ __archive_openssl_md5init(archive_md5_ctx *ctx)
 }
 
 static int
-__archive_openssl_md5update(archive_md5_ctx *ctx, const void *indata,
+__archive_md5update(archive_md5_ctx *ctx, const void *indata,
     size_t insize)
 {
   EVP_DigestUpdate(*ctx, indata, insize);
@@ -256,7 +256,7 @@ __archive_openssl_md5update(archive_md5_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_openssl_md5final(archive_md5_ctx *ctx, void *md)
+__archive_md5final(archive_md5_ctx *ctx, void *md)
 {
   /* HACK: archive_write_set_format_xar.c is finalizing empty contexts, so
    * this is meant to cope with that. Real fix is probably to fix
@@ -273,20 +273,20 @@ __archive_openssl_md5final(archive_md5_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_MD5_WIN)
 
 static int
-__archive_windowsapi_md5init(archive_md5_ctx *ctx)
+__archive_md5init(archive_md5_ctx *ctx)
 {
   return (win_crypto_init(ctx, CALG_MD5));
 }
 
 static int
-__archive_windowsapi_md5update(archive_md5_ctx *ctx, const void *indata,
+__archive_md5update(archive_md5_ctx *ctx, const void *indata,
     size_t insize)
 {
   return (win_crypto_Update(ctx, indata, insize));
 }
 
 static int
-__archive_windowsapi_md5final(archive_md5_ctx *ctx, void *md)
+__archive_md5final(archive_md5_ctx *ctx, void *md)
 {
   return (win_crypto_Final(md, 16, ctx));
 }
@@ -294,14 +294,14 @@ __archive_windowsapi_md5final(archive_md5_ctx *ctx, void *md)
 #else
 
 static int
-__archive_stub_md5init(archive_md5_ctx *ctx)
+__archive_md5init(archive_md5_ctx *ctx)
 {
        (void)ctx; /* UNUSED */
        return (ARCHIVE_FAILED);
 }
 
 static int
-__archive_stub_md5update(archive_md5_ctx *ctx, const void *indata,
+__archive_md5update(archive_md5_ctx *ctx, const void *indata,
     size_t insize)
 {
        (void)ctx; /* UNUSED */
@@ -311,7 +311,7 @@ __archive_stub_md5update(archive_md5_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_stub_md5final(archive_md5_ctx *ctx, void *md)
+__archive_md5final(archive_md5_ctx *ctx, void *md)
 {
        (void)ctx; /* UNUSED */
        (void)md; /* UNUSED */
@@ -324,14 +324,14 @@ __archive_stub_md5final(archive_md5_ctx *ctx, void *md)
 #if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
 
 static int
-__archive_libc_ripemd160init(archive_rmd160_ctx *ctx)
+__archive_ripemd160init(archive_rmd160_ctx *ctx)
 {
   RMD160Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libc_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
     size_t insize)
 {
   RMD160Update(ctx, indata, insize);
@@ -339,7 +339,7 @@ __archive_libc_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libc_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)
 {
   RMD160Final(md, ctx);
   return (ARCHIVE_OK);
@@ -348,14 +348,14 @@ __archive_libc_ripemd160final(archive_rmd160_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
 
 static int
-__archive_libmd_ripemd160init(archive_rmd160_ctx *ctx)
+__archive_ripemd160init(archive_rmd160_ctx *ctx)
 {
   RIPEMD160_Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libmd_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
     size_t insize)
 {
   RIPEMD160_Update(ctx, indata, insize);
@@ -363,7 +363,7 @@ __archive_libmd_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libmd_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)
 {
   RIPEMD160_Final(md, ctx);
   return (ARCHIVE_OK);
@@ -372,7 +372,7 @@ __archive_libmd_ripemd160final(archive_rmd160_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_RMD160_MBEDTLS)
 
 static int
-__archive_mbedtls_ripemd160init(archive_rmd160_ctx *ctx)
+__archive_ripemd160init(archive_rmd160_ctx *ctx)
 {
   mbedtls_ripemd160_init(ctx);
   if (mbedtls_ripemd160_starts_ret(ctx) == 0)
@@ -382,7 +382,7 @@ __archive_mbedtls_ripemd160init(archive_rmd160_ctx *ctx)
 }
 
 static int
-__archive_mbedtls_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
     size_t insize)
 {
   if (mbedtls_ripemd160_update_ret(ctx, indata, insize) == 0)
@@ -392,7 +392,7 @@ __archive_mbedtls_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_mbedtls_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)
 {
   if (mbedtls_ripemd160_finish_ret(ctx, md) == 0) {
     mbedtls_ripemd160_free(ctx);
@@ -406,14 +406,14 @@ __archive_mbedtls_ripemd160final(archive_rmd160_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
 
 static int
-__archive_nettle_ripemd160init(archive_rmd160_ctx *ctx)
+__archive_ripemd160init(archive_rmd160_ctx *ctx)
 {
   ripemd160_init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_nettle_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
     size_t insize)
 {
   ripemd160_update(ctx, insize, indata);
@@ -421,7 +421,7 @@ __archive_nettle_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_nettle_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)
 {
   ripemd160_digest(ctx, RIPEMD160_DIGEST_SIZE, md);
   return (ARCHIVE_OK);
@@ -430,7 +430,7 @@ __archive_nettle_ripemd160final(archive_rmd160_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
 
 static int
-__archive_openssl_ripemd160init(archive_rmd160_ctx *ctx)
+__archive_ripemd160init(archive_rmd160_ctx *ctx)
 {
   if ((*ctx = EVP_MD_CTX_new()) == NULL)
        return (ARCHIVE_FAILED);
@@ -439,7 +439,7 @@ __archive_openssl_ripemd160init(archive_rmd160_ctx *ctx)
 }
 
 static int
-__archive_openssl_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
     size_t insize)
 {
   EVP_DigestUpdate(*ctx, indata, insize);
@@ -447,7 +447,7 @@ __archive_openssl_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_openssl_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)
 {
   if (*ctx) {
     EVP_DigestFinal(*ctx, md, NULL);
@@ -460,14 +460,14 @@ __archive_openssl_ripemd160final(archive_rmd160_ctx *ctx, void *md)
 #else
 
 static int
-__archive_stub_ripemd160init(archive_rmd160_ctx *ctx)
+__archive_ripemd160init(archive_rmd160_ctx *ctx)
 {
        (void)ctx; /* UNUSED */
        return (ARCHIVE_FAILED);
 }
 
 static int
-__archive_stub_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
     size_t insize)
 {
        (void)ctx; /* UNUSED */
@@ -477,7 +477,7 @@ __archive_stub_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_stub_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)
 {
        (void)ctx; /* UNUSED */
        (void)md; /* UNUSED */
@@ -490,14 +490,14 @@ __archive_stub_ripemd160final(archive_rmd160_ctx *ctx, void *md)
 #if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
 
 static int
-__archive_libc_sha1init(archive_sha1_ctx *ctx)
+__archive_sha1init(archive_sha1_ctx *ctx)
 {
   SHA1Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libc_sha1update(archive_sha1_ctx *ctx, const void *indata,
+__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA1Update(ctx, indata, insize);
@@ -505,7 +505,7 @@ __archive_libc_sha1update(archive_sha1_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libc_sha1final(archive_sha1_ctx *ctx, void *md)
+__archive_sha1final(archive_sha1_ctx *ctx, void *md)
 {
   SHA1Final(md, ctx);
   return (ARCHIVE_OK);
@@ -514,14 +514,14 @@ __archive_libc_sha1final(archive_sha1_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
 
 static int
-__archive_libmd_sha1init(archive_sha1_ctx *ctx)
+__archive_sha1init(archive_sha1_ctx *ctx)
 {
   SHA1_Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libmd_sha1update(archive_sha1_ctx *ctx, const void *indata,
+__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA1_Update(ctx, indata, insize);
@@ -529,7 +529,7 @@ __archive_libmd_sha1update(archive_sha1_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libmd_sha1final(archive_sha1_ctx *ctx, void *md)
+__archive_sha1final(archive_sha1_ctx *ctx, void *md)
 {
   SHA1_Final(md, ctx);
   return (ARCHIVE_OK);
@@ -538,14 +538,14 @@ __archive_libmd_sha1final(archive_sha1_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
 
 static int
-__archive_libsystem_sha1init(archive_sha1_ctx *ctx)
+__archive_sha1init(archive_sha1_ctx *ctx)
 {
   CC_SHA1_Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libsystem_sha1update(archive_sha1_ctx *ctx, const void *indata,
+__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
     size_t insize)
 {
   CC_SHA1_Update(ctx, indata, insize);
@@ -553,7 +553,7 @@ __archive_libsystem_sha1update(archive_sha1_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libsystem_sha1final(archive_sha1_ctx *ctx, void *md)
+__archive_sha1final(archive_sha1_ctx *ctx, void *md)
 {
   CC_SHA1_Final(md, ctx);
   return (ARCHIVE_OK);
@@ -562,7 +562,7 @@ __archive_libsystem_sha1final(archive_sha1_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA1_MBEDTLS)
 
 static int
-__archive_mbedtls_sha1init(archive_sha1_ctx *ctx)
+__archive_sha1init(archive_sha1_ctx *ctx)
 {
   mbedtls_sha1_init(ctx);
   if (mbedtls_sha1_starts_ret(ctx) == 0)
@@ -572,7 +572,7 @@ __archive_mbedtls_sha1init(archive_sha1_ctx *ctx)
 }
 
 static int
-__archive_mbedtls_sha1update(archive_sha1_ctx *ctx, const void *indata,
+__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
     size_t insize)
 {
   if (mbedtls_sha1_update_ret(ctx, indata, insize) == 0)
@@ -582,7 +582,7 @@ __archive_mbedtls_sha1update(archive_sha1_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_mbedtls_sha1final(archive_sha1_ctx *ctx, void *md)
+__archive_sha1final(archive_sha1_ctx *ctx, void *md)
 {
   if (mbedtls_sha1_finish_ret(ctx, md) == 0) {
     mbedtls_sha1_free(ctx);
@@ -596,14 +596,14 @@ __archive_mbedtls_sha1final(archive_sha1_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
 
 static int
-__archive_nettle_sha1init(archive_sha1_ctx *ctx)
+__archive_sha1init(archive_sha1_ctx *ctx)
 {
   sha1_init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_nettle_sha1update(archive_sha1_ctx *ctx, const void *indata,
+__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
     size_t insize)
 {
   sha1_update(ctx, insize, indata);
@@ -611,7 +611,7 @@ __archive_nettle_sha1update(archive_sha1_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_nettle_sha1final(archive_sha1_ctx *ctx, void *md)
+__archive_sha1final(archive_sha1_ctx *ctx, void *md)
 {
   sha1_digest(ctx, SHA1_DIGEST_SIZE, md);
   return (ARCHIVE_OK);
@@ -620,7 +620,7 @@ __archive_nettle_sha1final(archive_sha1_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
 
 static int
-__archive_openssl_sha1init(archive_sha1_ctx *ctx)
+__archive_sha1init(archive_sha1_ctx *ctx)
 {
   if ((*ctx = EVP_MD_CTX_new()) == NULL)
        return (ARCHIVE_FAILED);
@@ -629,7 +629,7 @@ __archive_openssl_sha1init(archive_sha1_ctx *ctx)
 }
 
 static int
-__archive_openssl_sha1update(archive_sha1_ctx *ctx, const void *indata,
+__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
     size_t insize)
 {
   EVP_DigestUpdate(*ctx, indata, insize);
@@ -637,7 +637,7 @@ __archive_openssl_sha1update(archive_sha1_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_openssl_sha1final(archive_sha1_ctx *ctx, void *md)
+__archive_sha1final(archive_sha1_ctx *ctx, void *md)
 {
   /* HACK: archive_write_set_format_xar.c is finalizing empty contexts, so
    * this is meant to cope with that. Real fix is probably to fix
@@ -654,20 +654,20 @@ __archive_openssl_sha1final(archive_sha1_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
 
 static int
-__archive_windowsapi_sha1init(archive_sha1_ctx *ctx)
+__archive_sha1init(archive_sha1_ctx *ctx)
 {
   return (win_crypto_init(ctx, CALG_SHA1));
 }
 
 static int
-__archive_windowsapi_sha1update(archive_sha1_ctx *ctx, const void *indata,
+__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
     size_t insize)
 {
   return (win_crypto_Update(ctx, indata, insize));
 }
 
 static int
-__archive_windowsapi_sha1final(archive_sha1_ctx *ctx, void *md)
+__archive_sha1final(archive_sha1_ctx *ctx, void *md)
 {
   return (win_crypto_Final(md, 20, ctx));
 }
@@ -675,14 +675,14 @@ __archive_windowsapi_sha1final(archive_sha1_ctx *ctx, void *md)
 #else
 
 static int
-__archive_stub_sha1init(archive_sha1_ctx *ctx)
+__archive_sha1init(archive_sha1_ctx *ctx)
 {
        (void)ctx; /* UNUSED */
        return (ARCHIVE_FAILED);
 }
 
 static int
-__archive_stub_sha1update(archive_sha1_ctx *ctx, const void *indata,
+__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
     size_t insize)
 {
        (void)ctx; /* UNUSED */
@@ -692,7 +692,7 @@ __archive_stub_sha1update(archive_sha1_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_stub_sha1final(archive_sha1_ctx *ctx, void *md)
+__archive_sha1final(archive_sha1_ctx *ctx, void *md)
 {
        (void)ctx; /* UNUSED */
        (void)md; /* UNUSED */
@@ -705,14 +705,14 @@ __archive_stub_sha1final(archive_sha1_ctx *ctx, void *md)
 #if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
 
 static int
-__archive_libc_sha256init(archive_sha256_ctx *ctx)
+__archive_sha256init(archive_sha256_ctx *ctx)
 {
   SHA256_Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libc_sha256update(archive_sha256_ctx *ctx, const void *indata,
+__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA256_Update(ctx, indata, insize);
@@ -720,7 +720,7 @@ __archive_libc_sha256update(archive_sha256_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libc_sha256final(archive_sha256_ctx *ctx, void *md)
+__archive_sha256final(archive_sha256_ctx *ctx, void *md)
 {
   SHA256_Final(md, ctx);
   return (ARCHIVE_OK);
@@ -729,14 +729,14 @@ __archive_libc_sha256final(archive_sha256_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
 
 static int
-__archive_libc2_sha256init(archive_sha256_ctx *ctx)
+__archive_sha256init(archive_sha256_ctx *ctx)
 {
   SHA256Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libc2_sha256update(archive_sha256_ctx *ctx, const void *indata,
+__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA256Update(ctx, indata, insize);
@@ -744,7 +744,7 @@ __archive_libc2_sha256update(archive_sha256_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libc2_sha256final(archive_sha256_ctx *ctx, void *md)
+__archive_sha256final(archive_sha256_ctx *ctx, void *md)
 {
   SHA256Final(md, ctx);
   return (ARCHIVE_OK);
@@ -753,14 +753,14 @@ __archive_libc2_sha256final(archive_sha256_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
 
 static int
-__archive_libc3_sha256init(archive_sha256_ctx *ctx)
+__archive_sha256init(archive_sha256_ctx *ctx)
 {
   SHA256Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libc3_sha256update(archive_sha256_ctx *ctx, const void *indata,
+__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA256Update(ctx, indata, insize);
@@ -768,7 +768,7 @@ __archive_libc3_sha256update(archive_sha256_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libc3_sha256final(archive_sha256_ctx *ctx, void *md)
+__archive_sha256final(archive_sha256_ctx *ctx, void *md)
 {
   SHA256Final(md, ctx);
   return (ARCHIVE_OK);
@@ -777,14 +777,14 @@ __archive_libc3_sha256final(archive_sha256_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
 
 static int
-__archive_libmd_sha256init(archive_sha256_ctx *ctx)
+__archive_sha256init(archive_sha256_ctx *ctx)
 {
   SHA256_Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libmd_sha256update(archive_sha256_ctx *ctx, const void *indata,
+__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA256_Update(ctx, indata, insize);
@@ -792,7 +792,7 @@ __archive_libmd_sha256update(archive_sha256_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libmd_sha256final(archive_sha256_ctx *ctx, void *md)
+__archive_sha256final(archive_sha256_ctx *ctx, void *md)
 {
   SHA256_Final(md, ctx);
   return (ARCHIVE_OK);
@@ -801,14 +801,14 @@ __archive_libmd_sha256final(archive_sha256_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
 
 static int
-__archive_libsystem_sha256init(archive_sha256_ctx *ctx)
+__archive_sha256init(archive_sha256_ctx *ctx)
 {
   CC_SHA256_Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libsystem_sha256update(archive_sha256_ctx *ctx, const void *indata,
+__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
     size_t insize)
 {
   CC_SHA256_Update(ctx, indata, insize);
@@ -816,7 +816,7 @@ __archive_libsystem_sha256update(archive_sha256_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libsystem_sha256final(archive_sha256_ctx *ctx, void *md)
+__archive_sha256final(archive_sha256_ctx *ctx, void *md)
 {
   CC_SHA256_Final(md, ctx);
   return (ARCHIVE_OK);
@@ -825,7 +825,7 @@ __archive_libsystem_sha256final(archive_sha256_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA256_MBEDTLS)
 
 static int
-__archive_mbedtls_sha256init(archive_sha256_ctx *ctx)
+__archive_sha256init(archive_sha256_ctx *ctx)
 {
   mbedtls_sha256_init(ctx);
   if (mbedtls_sha256_starts_ret(ctx, 0) == 0)
@@ -835,7 +835,7 @@ __archive_mbedtls_sha256init(archive_sha256_ctx *ctx)
 }
 
 static int
-__archive_mbedtls_sha256update(archive_sha256_ctx *ctx, const void *indata,
+__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
     size_t insize)
 {
   if (mbedtls_sha256_update_ret(ctx, indata, insize) == 0)
@@ -845,7 +845,7 @@ __archive_mbedtls_sha256update(archive_sha256_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_mbedtls_sha256final(archive_sha256_ctx *ctx, void *md)
+__archive_sha256final(archive_sha256_ctx *ctx, void *md)
 {
   if (mbedtls_sha256_finish_ret(ctx, md) == 0) {
     mbedtls_sha256_free(ctx);
@@ -859,14 +859,14 @@ __archive_mbedtls_sha256final(archive_sha256_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
 
 static int
-__archive_nettle_sha256init(archive_sha256_ctx *ctx)
+__archive_sha256init(archive_sha256_ctx *ctx)
 {
   sha256_init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_nettle_sha256update(archive_sha256_ctx *ctx, const void *indata,
+__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
     size_t insize)
 {
   sha256_update(ctx, insize, indata);
@@ -874,7 +874,7 @@ __archive_nettle_sha256update(archive_sha256_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_nettle_sha256final(archive_sha256_ctx *ctx, void *md)
+__archive_sha256final(archive_sha256_ctx *ctx, void *md)
 {
   sha256_digest(ctx, SHA256_DIGEST_SIZE, md);
   return (ARCHIVE_OK);
@@ -883,7 +883,7 @@ __archive_nettle_sha256final(archive_sha256_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
 
 static int
-__archive_openssl_sha256init(archive_sha256_ctx *ctx)
+__archive_sha256init(archive_sha256_ctx *ctx)
 {
   if ((*ctx = EVP_MD_CTX_new()) == NULL)
        return (ARCHIVE_FAILED);
@@ -892,7 +892,7 @@ __archive_openssl_sha256init(archive_sha256_ctx *ctx)
 }
 
 static int
-__archive_openssl_sha256update(archive_sha256_ctx *ctx, const void *indata,
+__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
     size_t insize)
 {
   EVP_DigestUpdate(*ctx, indata, insize);
@@ -900,7 +900,7 @@ __archive_openssl_sha256update(archive_sha256_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_openssl_sha256final(archive_sha256_ctx *ctx, void *md)
+__archive_sha256final(archive_sha256_ctx *ctx, void *md)
 {
   if (*ctx) {
     EVP_DigestFinal(*ctx, md, NULL);
@@ -913,20 +913,20 @@ __archive_openssl_sha256final(archive_sha256_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
 
 static int
-__archive_windowsapi_sha256init(archive_sha256_ctx *ctx)
+__archive_sha256init(archive_sha256_ctx *ctx)
 {
   return (win_crypto_init(ctx, CALG_SHA_256));
 }
 
 static int
-__archive_windowsapi_sha256update(archive_sha256_ctx *ctx, const void *indata,
+__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
     size_t insize)
 {
   return (win_crypto_Update(ctx, indata, insize));
 }
 
 static int
-__archive_windowsapi_sha256final(archive_sha256_ctx *ctx, void *md)
+__archive_sha256final(archive_sha256_ctx *ctx, void *md)
 {
   return (win_crypto_Final(md, 32, ctx));
 }
@@ -934,14 +934,14 @@ __archive_windowsapi_sha256final(archive_sha256_ctx *ctx, void *md)
 #else
 
 static int
-__archive_stub_sha256init(archive_sha256_ctx *ctx)
+__archive_sha256init(archive_sha256_ctx *ctx)
 {
        (void)ctx; /* UNUSED */
        return (ARCHIVE_FAILED);
 }
 
 static int
-__archive_stub_sha256update(archive_sha256_ctx *ctx, const void *indata,
+__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
     size_t insize)
 {
        (void)ctx; /* UNUSED */
@@ -951,7 +951,7 @@ __archive_stub_sha256update(archive_sha256_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_stub_sha256final(archive_sha256_ctx *ctx, void *md)
+__archive_sha256final(archive_sha256_ctx *ctx, void *md)
 {
        (void)ctx; /* UNUSED */
        (void)md; /* UNUSED */
@@ -964,14 +964,14 @@ __archive_stub_sha256final(archive_sha256_ctx *ctx, void *md)
 #if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
 
 static int
-__archive_libc_sha384init(archive_sha384_ctx *ctx)
+__archive_sha384init(archive_sha384_ctx *ctx)
 {
   SHA384_Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libc_sha384update(archive_sha384_ctx *ctx, const void *indata,
+__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA384_Update(ctx, indata, insize);
@@ -979,7 +979,7 @@ __archive_libc_sha384update(archive_sha384_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libc_sha384final(archive_sha384_ctx *ctx, void *md)
+__archive_sha384final(archive_sha384_ctx *ctx, void *md)
 {
   SHA384_Final(md, ctx);
   return (ARCHIVE_OK);
@@ -988,14 +988,14 @@ __archive_libc_sha384final(archive_sha384_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
 
 static int
-__archive_libc2_sha384init(archive_sha384_ctx *ctx)
+__archive_sha384init(archive_sha384_ctx *ctx)
 {
   SHA384Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libc2_sha384update(archive_sha384_ctx *ctx, const void *indata,
+__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA384Update(ctx, indata, insize);
@@ -1003,7 +1003,7 @@ __archive_libc2_sha384update(archive_sha384_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libc2_sha384final(archive_sha384_ctx *ctx, void *md)
+__archive_sha384final(archive_sha384_ctx *ctx, void *md)
 {
   SHA384Final(md, ctx);
   return (ARCHIVE_OK);
@@ -1012,14 +1012,14 @@ __archive_libc2_sha384final(archive_sha384_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
 
 static int
-__archive_libc3_sha384init(archive_sha384_ctx *ctx)
+__archive_sha384init(archive_sha384_ctx *ctx)
 {
   SHA384Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libc3_sha384update(archive_sha384_ctx *ctx, const void *indata,
+__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA384Update(ctx, indata, insize);
@@ -1027,7 +1027,7 @@ __archive_libc3_sha384update(archive_sha384_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libc3_sha384final(archive_sha384_ctx *ctx, void *md)
+__archive_sha384final(archive_sha384_ctx *ctx, void *md)
 {
   SHA384Final(md, ctx);
   return (ARCHIVE_OK);
@@ -1036,14 +1036,14 @@ __archive_libc3_sha384final(archive_sha384_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
 
 static int
-__archive_libsystem_sha384init(archive_sha384_ctx *ctx)
+__archive_sha384init(archive_sha384_ctx *ctx)
 {
   CC_SHA384_Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libsystem_sha384update(archive_sha384_ctx *ctx, const void *indata,
+__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
     size_t insize)
 {
   CC_SHA384_Update(ctx, indata, insize);
@@ -1051,7 +1051,7 @@ __archive_libsystem_sha384update(archive_sha384_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libsystem_sha384final(archive_sha384_ctx *ctx, void *md)
+__archive_sha384final(archive_sha384_ctx *ctx, void *md)
 {
   CC_SHA384_Final(md, ctx);
   return (ARCHIVE_OK);
@@ -1060,7 +1060,7 @@ __archive_libsystem_sha384final(archive_sha384_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA384_MBEDTLS)
 
 static int
-__archive_mbedtls_sha384init(archive_sha384_ctx *ctx)
+__archive_sha384init(archive_sha384_ctx *ctx)
 {
   mbedtls_sha512_init(ctx);
   if (mbedtls_sha512_starts_ret(ctx, 1) == 0)
@@ -1070,7 +1070,7 @@ __archive_mbedtls_sha384init(archive_sha384_ctx *ctx)
 }
 
 static int
-__archive_mbedtls_sha384update(archive_sha384_ctx *ctx, const void *indata,
+__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
     size_t insize)
 {
   if (mbedtls_sha512_update_ret(ctx, indata, insize) == 0)
@@ -1080,7 +1080,7 @@ __archive_mbedtls_sha384update(archive_sha384_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_mbedtls_sha384final(archive_sha384_ctx *ctx, void *md)
+__archive_sha384final(archive_sha384_ctx *ctx, void *md)
 {
   if (mbedtls_sha512_finish_ret(ctx, md) == 0) {
     mbedtls_sha512_free(ctx);
@@ -1094,14 +1094,14 @@ __archive_mbedtls_sha384final(archive_sha384_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
 
 static int
-__archive_nettle_sha384init(archive_sha384_ctx *ctx)
+__archive_sha384init(archive_sha384_ctx *ctx)
 {
   sha384_init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_nettle_sha384update(archive_sha384_ctx *ctx, const void *indata,
+__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
     size_t insize)
 {
   sha384_update(ctx, insize, indata);
@@ -1109,7 +1109,7 @@ __archive_nettle_sha384update(archive_sha384_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_nettle_sha384final(archive_sha384_ctx *ctx, void *md)
+__archive_sha384final(archive_sha384_ctx *ctx, void *md)
 {
   sha384_digest(ctx, SHA384_DIGEST_SIZE, md);
   return (ARCHIVE_OK);
@@ -1118,7 +1118,7 @@ __archive_nettle_sha384final(archive_sha384_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
 
 static int
-__archive_openssl_sha384init(archive_sha384_ctx *ctx)
+__archive_sha384init(archive_sha384_ctx *ctx)
 {
   if ((*ctx = EVP_MD_CTX_new()) == NULL)
        return (ARCHIVE_FAILED);
@@ -1127,7 +1127,7 @@ __archive_openssl_sha384init(archive_sha384_ctx *ctx)
 }
 
 static int
-__archive_openssl_sha384update(archive_sha384_ctx *ctx, const void *indata,
+__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
     size_t insize)
 {
   EVP_DigestUpdate(*ctx, indata, insize);
@@ -1135,7 +1135,7 @@ __archive_openssl_sha384update(archive_sha384_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_openssl_sha384final(archive_sha384_ctx *ctx, void *md)
+__archive_sha384final(archive_sha384_ctx *ctx, void *md)
 {
   if (*ctx) {
     EVP_DigestFinal(*ctx, md, NULL);
@@ -1148,20 +1148,20 @@ __archive_openssl_sha384final(archive_sha384_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
 
 static int
-__archive_windowsapi_sha384init(archive_sha384_ctx *ctx)
+__archive_sha384init(archive_sha384_ctx *ctx)
 {
   return (win_crypto_init(ctx, CALG_SHA_384));
 }
 
 static int
-__archive_windowsapi_sha384update(archive_sha384_ctx *ctx, const void *indata,
+__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
     size_t insize)
 {
   return (win_crypto_Update(ctx, indata, insize));
 }
 
 static int
-__archive_windowsapi_sha384final(archive_sha384_ctx *ctx, void *md)
+__archive_sha384final(archive_sha384_ctx *ctx, void *md)
 {
   return (win_crypto_Final(md, 48, ctx));
 }
@@ -1169,14 +1169,14 @@ __archive_windowsapi_sha384final(archive_sha384_ctx *ctx, void *md)
 #else
 
 static int
-__archive_stub_sha384init(archive_sha384_ctx *ctx)
+__archive_sha384init(archive_sha384_ctx *ctx)
 {
        (void)ctx; /* UNUSED */
        return (ARCHIVE_FAILED);
 }
 
 static int
-__archive_stub_sha384update(archive_sha384_ctx *ctx, const void *indata,
+__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
     size_t insize)
 {
        (void)ctx; /* UNUSED */
@@ -1186,7 +1186,7 @@ __archive_stub_sha384update(archive_sha384_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_stub_sha384final(archive_sha384_ctx *ctx, void *md)
+__archive_sha384final(archive_sha384_ctx *ctx, void *md)
 {
        (void)ctx; /* UNUSED */
        (void)md; /* UNUSED */
@@ -1199,14 +1199,14 @@ __archive_stub_sha384final(archive_sha384_ctx *ctx, void *md)
 #if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
 
 static int
-__archive_libc_sha512init(archive_sha512_ctx *ctx)
+__archive_sha512init(archive_sha512_ctx *ctx)
 {
   SHA512_Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libc_sha512update(archive_sha512_ctx *ctx, const void *indata,
+__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA512_Update(ctx, indata, insize);
@@ -1214,7 +1214,7 @@ __archive_libc_sha512update(archive_sha512_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libc_sha512final(archive_sha512_ctx *ctx, void *md)
+__archive_sha512final(archive_sha512_ctx *ctx, void *md)
 {
   SHA512_Final(md, ctx);
   return (ARCHIVE_OK);
@@ -1223,14 +1223,14 @@ __archive_libc_sha512final(archive_sha512_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
 
 static int
-__archive_libc2_sha512init(archive_sha512_ctx *ctx)
+__archive_sha512init(archive_sha512_ctx *ctx)
 {
   SHA512Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libc2_sha512update(archive_sha512_ctx *ctx, const void *indata,
+__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA512Update(ctx, indata, insize);
@@ -1238,7 +1238,7 @@ __archive_libc2_sha512update(archive_sha512_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libc2_sha512final(archive_sha512_ctx *ctx, void *md)
+__archive_sha512final(archive_sha512_ctx *ctx, void *md)
 {
   SHA512Final(md, ctx);
   return (ARCHIVE_OK);
@@ -1247,14 +1247,14 @@ __archive_libc2_sha512final(archive_sha512_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
 
 static int
-__archive_libc3_sha512init(archive_sha512_ctx *ctx)
+__archive_sha512init(archive_sha512_ctx *ctx)
 {
   SHA512Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libc3_sha512update(archive_sha512_ctx *ctx, const void *indata,
+__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA512Update(ctx, indata, insize);
@@ -1262,7 +1262,7 @@ __archive_libc3_sha512update(archive_sha512_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libc3_sha512final(archive_sha512_ctx *ctx, void *md)
+__archive_sha512final(archive_sha512_ctx *ctx, void *md)
 {
   SHA512Final(md, ctx);
   return (ARCHIVE_OK);
@@ -1271,14 +1271,14 @@ __archive_libc3_sha512final(archive_sha512_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
 
 static int
-__archive_libmd_sha512init(archive_sha512_ctx *ctx)
+__archive_sha512init(archive_sha512_ctx *ctx)
 {
   SHA512_Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libmd_sha512update(archive_sha512_ctx *ctx, const void *indata,
+__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
     size_t insize)
 {
   SHA512_Update(ctx, indata, insize);
@@ -1286,7 +1286,7 @@ __archive_libmd_sha512update(archive_sha512_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libmd_sha512final(archive_sha512_ctx *ctx, void *md)
+__archive_sha512final(archive_sha512_ctx *ctx, void *md)
 {
   SHA512_Final(md, ctx);
   return (ARCHIVE_OK);
@@ -1295,14 +1295,14 @@ __archive_libmd_sha512final(archive_sha512_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
 
 static int
-__archive_libsystem_sha512init(archive_sha512_ctx *ctx)
+__archive_sha512init(archive_sha512_ctx *ctx)
 {
   CC_SHA512_Init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_libsystem_sha512update(archive_sha512_ctx *ctx, const void *indata,
+__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
     size_t insize)
 {
   CC_SHA512_Update(ctx, indata, insize);
@@ -1310,7 +1310,7 @@ __archive_libsystem_sha512update(archive_sha512_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_libsystem_sha512final(archive_sha512_ctx *ctx, void *md)
+__archive_sha512final(archive_sha512_ctx *ctx, void *md)
 {
   CC_SHA512_Final(md, ctx);
   return (ARCHIVE_OK);
@@ -1319,7 +1319,7 @@ __archive_libsystem_sha512final(archive_sha512_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA512_MBEDTLS)
 
 static int
-__archive_mbedtls_sha512init(archive_sha512_ctx *ctx)
+__archive_sha512init(archive_sha512_ctx *ctx)
 {
   mbedtls_sha512_init(ctx);
   if (mbedtls_sha512_starts_ret(ctx, 0) == 0)
@@ -1329,7 +1329,7 @@ __archive_mbedtls_sha512init(archive_sha512_ctx *ctx)
 }
 
 static int
-__archive_mbedtls_sha512update(archive_sha512_ctx *ctx, const void *indata,
+__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
     size_t insize)
 {
   if (mbedtls_sha512_update_ret(ctx, indata, insize) == 0)
@@ -1339,7 +1339,7 @@ __archive_mbedtls_sha512update(archive_sha512_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_mbedtls_sha512final(archive_sha512_ctx *ctx, void *md)
+__archive_sha512final(archive_sha512_ctx *ctx, void *md)
 {
   if (mbedtls_sha512_finish_ret(ctx, md) == 0) {
     mbedtls_sha512_free(ctx);
@@ -1353,14 +1353,14 @@ __archive_mbedtls_sha512final(archive_sha512_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
 
 static int
-__archive_nettle_sha512init(archive_sha512_ctx *ctx)
+__archive_sha512init(archive_sha512_ctx *ctx)
 {
   sha512_init(ctx);
   return (ARCHIVE_OK);
 }
 
 static int
-__archive_nettle_sha512update(archive_sha512_ctx *ctx, const void *indata,
+__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
     size_t insize)
 {
   sha512_update(ctx, insize, indata);
@@ -1368,7 +1368,7 @@ __archive_nettle_sha512update(archive_sha512_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_nettle_sha512final(archive_sha512_ctx *ctx, void *md)
+__archive_sha512final(archive_sha512_ctx *ctx, void *md)
 {
   sha512_digest(ctx, SHA512_DIGEST_SIZE, md);
   return (ARCHIVE_OK);
@@ -1377,7 +1377,7 @@ __archive_nettle_sha512final(archive_sha512_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
 
 static int
-__archive_openssl_sha512init(archive_sha512_ctx *ctx)
+__archive_sha512init(archive_sha512_ctx *ctx)
 {
   if ((*ctx = EVP_MD_CTX_new()) == NULL)
        return (ARCHIVE_FAILED);
@@ -1386,7 +1386,7 @@ __archive_openssl_sha512init(archive_sha512_ctx *ctx)
 }
 
 static int
-__archive_openssl_sha512update(archive_sha512_ctx *ctx, const void *indata,
+__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
     size_t insize)
 {
   EVP_DigestUpdate(*ctx, indata, insize);
@@ -1394,7 +1394,7 @@ __archive_openssl_sha512update(archive_sha512_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_openssl_sha512final(archive_sha512_ctx *ctx, void *md)
+__archive_sha512final(archive_sha512_ctx *ctx, void *md)
 {
   if (*ctx) {
     EVP_DigestFinal(*ctx, md, NULL);
@@ -1407,20 +1407,20 @@ __archive_openssl_sha512final(archive_sha512_ctx *ctx, void *md)
 #elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
 
 static int
-__archive_windowsapi_sha512init(archive_sha512_ctx *ctx)
+__archive_sha512init(archive_sha512_ctx *ctx)
 {
   return (win_crypto_init(ctx, CALG_SHA_512));
 }
 
 static int
-__archive_windowsapi_sha512update(archive_sha512_ctx *ctx, const void *indata,
+__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
     size_t insize)
 {
   return (win_crypto_Update(ctx, indata, insize));
 }
 
 static int
-__archive_windowsapi_sha512final(archive_sha512_ctx *ctx, void *md)
+__archive_sha512final(archive_sha512_ctx *ctx, void *md)
 {
   return (win_crypto_Final(md, 64, ctx));
 }
@@ -1428,14 +1428,14 @@ __archive_windowsapi_sha512final(archive_sha512_ctx *ctx, void *md)
 #else
 
 static int
-__archive_stub_sha512init(archive_sha512_ctx *ctx)
+__archive_sha512init(archive_sha512_ctx *ctx)
 {
        (void)ctx; /* UNUSED */
        return (ARCHIVE_FAILED);
 }
 
 static int
-__archive_stub_sha512update(archive_sha512_ctx *ctx, const void *indata,
+__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
     size_t insize)
 {
        (void)ctx; /* UNUSED */
@@ -1445,7 +1445,7 @@ __archive_stub_sha512update(archive_sha512_ctx *ctx, const void *indata,
 }
 
 static int
-__archive_stub_sha512final(archive_sha512_ctx *ctx, void *md)
+__archive_sha512final(archive_sha512_ctx *ctx, void *md)
 {
        (void)ctx; /* UNUSED */
        (void)md; /* UNUSED */
@@ -1468,224 +1468,32 @@ __archive_stub_sha512final(archive_sha512_ctx *ctx, void *md)
 const struct archive_digest __archive_digest =
 {
 /* MD5 */
-#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
-  &__archive_libc_md5init,
-  &__archive_libc_md5update,
-  &__archive_libc_md5final,
-#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
-  &__archive_libmd_md5init,
-  &__archive_libmd_md5update,
-  &__archive_libmd_md5final,
-#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
-  &__archive_libsystem_md5init,
-  &__archive_libsystem_md5update,
-  &__archive_libsystem_md5final,
-#elif defined(ARCHIVE_CRYPTO_MD5_MBEDTLS)
-  &__archive_mbedtls_md5init,
-  &__archive_mbedtls_md5update,
-  &__archive_mbedtls_md5final,
-#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
-  &__archive_nettle_md5init,
-  &__archive_nettle_md5update,
-  &__archive_nettle_md5final,
-#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
-  &__archive_openssl_md5init,
-  &__archive_openssl_md5update,
-  &__archive_openssl_md5final,
-#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
-  &__archive_windowsapi_md5init,
-  &__archive_windowsapi_md5update,
-  &__archive_windowsapi_md5final,
-#elif !defined(ARCHIVE_MD5_COMPILE_TEST)
-  &__archive_stub_md5init,
-  &__archive_stub_md5update,
-  &__archive_stub_md5final,
-#endif
+  &__archive_md5init,
+  &__archive_md5update,
+  &__archive_md5final,
 
 /* RIPEMD160 */
-#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
-  &__archive_libc_ripemd160init,
-  &__archive_libc_ripemd160update,
-  &__archive_libc_ripemd160final,
-#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
-  &__archive_libmd_ripemd160init,
-  &__archive_libmd_ripemd160update,
-  &__archive_libmd_ripemd160final,
-#elif defined(ARCHIVE_CRYPTO_RMD160_MBEDTLS)
-  &__archive_mbedtls_ripemd160init,
-  &__archive_mbedtls_ripemd160update,
-  &__archive_mbedtls_ripemd160final,
-#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
-  &__archive_nettle_ripemd160init,
-  &__archive_nettle_ripemd160update,
-  &__archive_nettle_ripemd160final,
-#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
-  &__archive_openssl_ripemd160init,
-  &__archive_openssl_ripemd160update,
-  &__archive_openssl_ripemd160final,
-#elif !defined(ARCHIVE_RMD160_COMPILE_TEST)
-  &__archive_stub_ripemd160init,
-  &__archive_stub_ripemd160update,
-  &__archive_stub_ripemd160final,
-#endif
+  &__archive_ripemd160init,
+  &__archive_ripemd160update,
+  &__archive_ripemd160final,
 
 /* SHA1 */
-#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
-  &__archive_libc_sha1init,
-  &__archive_libc_sha1update,
-  &__archive_libc_sha1final,
-#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
-  &__archive_libmd_sha1init,
-  &__archive_libmd_sha1update,
-  &__archive_libmd_sha1final,
-#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
-  &__archive_libsystem_sha1init,
-  &__archive_libsystem_sha1update,
-  &__archive_libsystem_sha1final,
-#elif defined(ARCHIVE_CRYPTO_SHA1_MBEDTLS)
-  &__archive_mbedtls_sha1init,
-  &__archive_mbedtls_sha1update,
-  &__archive_mbedtls_sha1final,
-#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
-  &__archive_nettle_sha1init,
-  &__archive_nettle_sha1update,
-  &__archive_nettle_sha1final,
-#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
-  &__archive_openssl_sha1init,
-  &__archive_openssl_sha1update,
-  &__archive_openssl_sha1final,
-#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
-  &__archive_windowsapi_sha1init,
-  &__archive_windowsapi_sha1update,
-  &__archive_windowsapi_sha1final,
-#elif !defined(ARCHIVE_SHA1_COMPILE_TEST)
-  &__archive_stub_sha1init,
-  &__archive_stub_sha1update,
-  &__archive_stub_sha1final,
-#endif
+  &__archive_sha1init,
+  &__archive_sha1update,
+  &__archive_sha1final,
 
 /* SHA256 */
-#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
-  &__archive_libc_sha256init,
-  &__archive_libc_sha256update,
-  &__archive_libc_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
-  &__archive_libc2_sha256init,
-  &__archive_libc2_sha256update,
-  &__archive_libc2_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
-  &__archive_libc3_sha256init,
-  &__archive_libc3_sha256update,
-  &__archive_libc3_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
-  &__archive_libmd_sha256init,
-  &__archive_libmd_sha256update,
-  &__archive_libmd_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
-  &__archive_libsystem_sha256init,
-  &__archive_libsystem_sha256update,
-  &__archive_libsystem_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_MBEDTLS)
-  &__archive_mbedtls_sha256init,
-  &__archive_mbedtls_sha256update,
-  &__archive_mbedtls_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
-  &__archive_nettle_sha256init,
-  &__archive_nettle_sha256update,
-  &__archive_nettle_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
-  &__archive_openssl_sha256init,
-  &__archive_openssl_sha256update,
-  &__archive_openssl_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
-  &__archive_windowsapi_sha256init,
-  &__archive_windowsapi_sha256update,
-  &__archive_windowsapi_sha256final,
-#elif !defined(ARCHIVE_SHA256_COMPILE_TEST)
-  &__archive_stub_sha256init,
-  &__archive_stub_sha256update,
-  &__archive_stub_sha256final,
-#endif
+  &__archive_sha256init,
+  &__archive_sha256update,
+  &__archive_sha256final,
 
 /* SHA384 */
-#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
-  &__archive_libc_sha384init,
-  &__archive_libc_sha384update,
-  &__archive_libc_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
-  &__archive_libc2_sha384init,
-  &__archive_libc2_sha384update,
-  &__archive_libc2_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
-  &__archive_libc3_sha384init,
-  &__archive_libc3_sha384update,
-  &__archive_libc3_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
-  &__archive_libsystem_sha384init,
-  &__archive_libsystem_sha384update,
-  &__archive_libsystem_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_MBEDTLS)
-  &__archive_mbedtls_sha384init,
-  &__archive_mbedtls_sha384update,
-  &__archive_mbedtls_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
-  &__archive_nettle_sha384init,
-  &__archive_nettle_sha384update,
-  &__archive_nettle_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
-  &__archive_openssl_sha384init,
-  &__archive_openssl_sha384update,
-  &__archive_openssl_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
-  &__archive_windowsapi_sha384init,
-  &__archive_windowsapi_sha384update,
-  &__archive_windowsapi_sha384final,
-#elif !defined(ARCHIVE_SHA384_COMPILE_TEST)
-  &__archive_stub_sha384init,
-  &__archive_stub_sha384update,
-  &__archive_stub_sha384final,
-#endif
+  &__archive_sha384init,
+  &__archive_sha384update,
+  &__archive_sha384final,
 
 /* SHA512 */
-#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
-  &__archive_libc_sha512init,
-  &__archive_libc_sha512update,
-  &__archive_libc_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
-  &__archive_libc2_sha512init,
-  &__archive_libc2_sha512update,
-  &__archive_libc2_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
-  &__archive_libc3_sha512init,
-  &__archive_libc3_sha512update,
-  &__archive_libc3_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
-  &__archive_libmd_sha512init,
-  &__archive_libmd_sha512update,
-  &__archive_libmd_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
-  &__archive_libsystem_sha512init,
-  &__archive_libsystem_sha512update,
-  &__archive_libsystem_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_MBEDTLS)
-  &__archive_mbedtls_sha512init,
-  &__archive_mbedtls_sha512update,
-  &__archive_mbedtls_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
-  &__archive_nettle_sha512init,
-  &__archive_nettle_sha512update,
-  &__archive_nettle_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
-  &__archive_openssl_sha512init,
-  &__archive_openssl_sha512update,
-  &__archive_openssl_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
-  &__archive_windowsapi_sha512init,
-  &__archive_windowsapi_sha512update,
-  &__archive_windowsapi_sha512final
-#elif !defined(ARCHIVE_SHA512_COMPILE_TEST)
-  &__archive_stub_sha512init,
-  &__archive_stub_sha512update,
-  &__archive_stub_sha512final
-#endif
+  &__archive_sha512init,
+  &__archive_sha512update,
+  &__archive_sha512final
 };
index 15312ee..9b3bd66 100644 (file)
 #ifndef __LIBARCHIVE_BUILD
 #error This header is only to be used internally to libarchive.
 #endif
+#ifndef __LIBARCHIVE_CONFIG_H_INCLUDED
+#error "Should have include config.h first!"
+#endif
+
 /*
  * Crypto support in various Operating Systems:
  *
index a15e98c..ca7a4bd 100644 (file)
@@ -208,6 +208,19 @@ archive_entry_clone(struct archive_entry *entry)
 
        /* Copy encryption status */
        entry2->encryption = entry->encryption;
+
+       /* Copy digests */
+#define copy_digest(_e2, _e, _t) \
+       memcpy(_e2->digest._t, _e->digest._t, sizeof(_e2->digest._t))
+
+       copy_digest(entry2, entry, md5);
+       copy_digest(entry2, entry, rmd160);
+       copy_digest(entry2, entry, sha1);
+       copy_digest(entry2, entry, sha256);
+       copy_digest(entry2, entry, sha384);
+       copy_digest(entry2, entry, sha512);
+
+#undef copy_digest
        
        /* Copy ACL data over. */
        archive_acl_copy(&entry2->acl, &entry->acl);
@@ -353,7 +366,7 @@ archive_entry_devminor(struct archive_entry *entry)
                return minor(entry->ae_stat.aest_dev);
 }
 
-mode_t
+__LA_MODE_T
 archive_entry_filetype(struct archive_entry *entry)
 {
        return (AE_IFMT & entry->acl.mode);
@@ -450,7 +463,7 @@ int
 _archive_entry_gname_l(struct archive_entry *entry,
     const char **p, size_t *len, struct archive_string_conv *sc)
 {
-       return (archive_mstring_get_mbs_l(&entry->ae_gname, p, len, sc));
+       return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_gname, p, len, sc));
 }
 
 const char *
@@ -504,7 +517,7 @@ _archive_entry_hardlink_l(struct archive_entry *entry,
                *len = 0;
                return (0);
        }
-       return (archive_mstring_get_mbs_l(&entry->ae_hardlink, p, len, sc));
+       return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_hardlink, p, len, sc));
 }
 
 la_int64_t
@@ -525,7 +538,7 @@ archive_entry_ino64(struct archive_entry *entry)
        return (entry->ae_stat.aest_ino);
 }
 
-mode_t
+__LA_MODE_T
 archive_entry_mode(struct archive_entry *entry)
 {
        return (entry->acl.mode);
@@ -595,10 +608,10 @@ int
 _archive_entry_pathname_l(struct archive_entry *entry,
     const char **p, size_t *len, struct archive_string_conv *sc)
 {
-       return (archive_mstring_get_mbs_l(&entry->ae_pathname, p, len, sc));
+       return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_pathname, p, len, sc));
 }
 
-mode_t
+__LA_MODE_T
 archive_entry_perm(struct archive_entry *entry)
 {
        return (~AE_IFMT & entry->acl.mode);
@@ -723,7 +736,7 @@ _archive_entry_symlink_l(struct archive_entry *entry,
                *len = 0;
                return (0);
        }
-       return (archive_mstring_get_mbs_l( &entry->ae_symlink, p, len, sc));
+       return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_symlink, p, len, sc));
 }
 
 la_int64_t
@@ -769,7 +782,7 @@ int
 _archive_entry_uname_l(struct archive_entry *entry,
     const char **p, size_t *len, struct archive_string_conv *sc)
 {
-       return (archive_mstring_get_mbs_l(&entry->ae_uname, p, len, sc));
+       return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_uname, p, len, sc));
 }
 
 int
@@ -1416,6 +1429,62 @@ archive_entry_copy_mac_metadata(struct archive_entry *entry,
   }
 }
 
+/* Digest handling */
+const unsigned char *
+archive_entry_digest(struct archive_entry *entry, int type)
+{
+       switch (type) {
+       case ARCHIVE_ENTRY_DIGEST_MD5:
+               return entry->digest.md5;
+       case ARCHIVE_ENTRY_DIGEST_RMD160:
+               return entry->digest.rmd160;
+       case ARCHIVE_ENTRY_DIGEST_SHA1:
+               return entry->digest.sha1;
+       case ARCHIVE_ENTRY_DIGEST_SHA256:
+               return entry->digest.sha256;
+       case ARCHIVE_ENTRY_DIGEST_SHA384:
+               return entry->digest.sha384;
+       case ARCHIVE_ENTRY_DIGEST_SHA512:
+               return entry->digest.sha512;
+       default:
+               return NULL;
+       }
+}
+
+int
+archive_entry_set_digest(struct archive_entry *entry, int type,
+    const unsigned char *digest)
+{
+#define copy_digest(_e, _t, _d)\
+       memcpy(_e->digest._t, _d, sizeof(_e->digest._t))
+
+       switch (type) {
+       case ARCHIVE_ENTRY_DIGEST_MD5:
+               copy_digest(entry, md5, digest);
+               break;
+       case ARCHIVE_ENTRY_DIGEST_RMD160:
+               copy_digest(entry, rmd160, digest);
+               break;
+       case ARCHIVE_ENTRY_DIGEST_SHA1:
+               copy_digest(entry, sha1, digest);
+               break;
+       case ARCHIVE_ENTRY_DIGEST_SHA256:
+               copy_digest(entry, sha256, digest);
+               break;
+       case ARCHIVE_ENTRY_DIGEST_SHA384:
+               copy_digest(entry, sha384, digest);
+               break;
+       case ARCHIVE_ENTRY_DIGEST_SHA512:
+               copy_digest(entry, sha512, digest);
+               break;
+       default:
+               return ARCHIVE_WARN;
+       }
+
+       return ARCHIVE_OK;
+#undef copy_digest
+}
+
 /*
  * ACL management.  The following would, of course, be a lot simpler
  * if: 1) the last draft of POSIX.1e were a really thorough and
index 0053faa..21e89d2 100644 (file)
@@ -30,7 +30,7 @@
 #define        ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define        ARCHIVE_VERSION_NUMBER 3004002
+#define        ARCHIVE_VERSION_NUMBER 3005001
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
@@ -394,6 +394,19 @@ __LA_DECL const void * archive_entry_mac_metadata(struct archive_entry *, size_t
 __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const void *, size_t);
 
 /*
+ * Digest routine. This is used to query the raw hex digest for the
+ * given entry. The type of digest is provided as an argument.
+ */
+#define ARCHIVE_ENTRY_DIGEST_MD5              0x00000001
+#define ARCHIVE_ENTRY_DIGEST_RMD160           0x00000002
+#define ARCHIVE_ENTRY_DIGEST_SHA1             0x00000003
+#define ARCHIVE_ENTRY_DIGEST_SHA256           0x00000004
+#define ARCHIVE_ENTRY_DIGEST_SHA384           0x00000005
+#define ARCHIVE_ENTRY_DIGEST_SHA512           0x00000006
+
+__LA_DECL const unsigned char * archive_entry_digest(struct archive_entry *, int /* type */);
+
+/*
  * ACL routines.  This used to simply store and return text-format ACL
  * strings, but that proved insufficient for a number of reasons:
  *   = clients need control over uname/uid and gname/gid mappings
index 2b9a084..cf4deb2 100644 (file)
@@ -50,6 +50,15 @@ struct ae_sparse {
        int64_t  length;
 };
 
+struct ae_digest {
+       unsigned char md5[16];
+       unsigned char rmd160[20];
+       unsigned char sha1[20];
+       unsigned char sha256[32];
+       unsigned char sha384[48];
+       unsigned char sha512[64];
+};
+
 /*
  * Description of an archive entry.
  *
@@ -162,6 +171,9 @@ struct archive_entry {
        void *mac_metadata;
        size_t mac_metadata_size;
 
+       /* Digest support. */
+       struct ae_digest digest;
+
        /* ACL support. */
        struct archive_acl    acl;
 
@@ -181,4 +193,8 @@ struct archive_entry {
        int ae_symlink_type;
 };
 
+int
+archive_entry_set_digest(struct archive_entry *entry, int type,
+    const unsigned char *digest);
+
 #endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
index aa5c8e0..29a53f7 100644 (file)
@@ -215,9 +215,9 @@ and
 set and unset the size, respectively.
 .Pp
 The number of references (hardlinks) can be obtained by calling
-.Fn archive_entry_nlinks
+.Fn archive_entry_nlink
 and set with
-.Fn archive_entry_set_nlinks .
+.Fn archive_entry_set_nlink .
 .Ss Identifying unique files
 The functions
 .Fn archive_entry_dev
index 4029395..cc3f778 100644 (file)
@@ -4,7 +4,7 @@ This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
 
 #include "archive_platform.h"
 
-#include <memory.h>
+#include <stdlib.h>
 
 #include "archive_ppmd7_private.h"
 
index 4a933b2..c59f051 100644 (file)
@@ -892,15 +892,16 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
                        len = a->read_data_remaining;
                        if (len > s)
                                len = s;
-                       if (len)
+                       if (len) {
                                memcpy(dest, a->read_data_block, len);
-                       s -= len;
-                       a->read_data_block += len;
-                       a->read_data_remaining -= len;
-                       a->read_data_output_offset += len;
-                       a->read_data_offset += len;
-                       dest += len;
-                       bytes_read += len;
+                               s -= len;
+                               a->read_data_block += len;
+                               a->read_data_remaining -= len;
+                               a->read_data_output_offset += len;
+                               a->read_data_offset += len;
+                               dest += len;
+                               bytes_read += len;
+                       }
                }
        }
        a->read_data_is_posix_read = 0;
index cf821b5..f0b1ab9 100644 (file)
@@ -57,6 +57,10 @@ insert_passphrase_to_head(struct archive_read *a,
 {
        p->next = a->passphrases.first;
        a->passphrases.first = p;
+       if (&a->passphrases.first == a->passphrases.last) {
+               a->passphrases.last = &p->next;
+               p->next = NULL;
+       }
 }
 
 static struct archive_read_passphrase *
index 2a8cec8..9c9cf38 100644 (file)
@@ -103,6 +103,10 @@ __FBSDID("$FreeBSD");
 
 static int setup_mac_metadata(struct archive_read_disk *,
     struct archive_entry *, int *fd);
+#ifdef ARCHIVE_XATTR_FREEBSD
+static int setup_xattrs_namespace(struct archive_read_disk *,
+    struct archive_entry *, int *, int);
+#endif
 static int setup_xattrs(struct archive_read_disk *,
     struct archive_entry *, int *fd);
 static int setup_sparse(struct archive_read_disk *,
@@ -701,14 +705,13 @@ setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
 }
 
 static int
-setup_xattrs(struct archive_read_disk *a,
-    struct archive_entry *entry, int *fd)
+setup_xattrs_namespace(struct archive_read_disk *a,
+    struct archive_entry *entry, int *fd, int namespace)
 {
        char buff[512];
        char *list, *p;
        ssize_t list_size;
        const char *path;
-       int namespace = EXTATTR_NAMESPACE_USER;
 
        path = NULL;
 
@@ -727,6 +730,8 @@ setup_xattrs(struct archive_read_disk *a,
 
        if (list_size == -1 && errno == EOPNOTSUPP)
                return (ARCHIVE_OK);
+       if (list_size == -1 && errno == EPERM)
+               return (ARCHIVE_OK);
        if (list_size == -1) {
                archive_set_error(&a->archive, errno,
                        "Couldn't list extended attributes");
@@ -760,7 +765,17 @@ setup_xattrs(struct archive_read_disk *a,
                size_t len = 255 & (int)*p;
                char *name;
 
-               strcpy(buff, "user.");
+               if (namespace == EXTATTR_NAMESPACE_SYSTEM) {
+                       if (!strcmp(p + 1, "nfs4.acl") ||
+                           !strcmp(p + 1, "posix1e.acl_access") ||
+                           !strcmp(p + 1, "posix1e.acl_default")) {
+                               p += 1 + len;
+                               continue;
+                       }
+                       strcpy(buff, "system.");
+               } else {
+                       strcpy(buff, "user.");
+               }
                name = buff + strlen(buff);
                memcpy(name, p + 1, len);
                name[len] = '\0';
@@ -772,6 +787,31 @@ setup_xattrs(struct archive_read_disk *a,
        return (ARCHIVE_OK);
 }
 
+static int
+setup_xattrs(struct archive_read_disk *a,
+    struct archive_entry *entry, int *fd)
+{
+       int namespaces[2];
+       int i, res;
+
+       namespaces[0] = EXTATTR_NAMESPACE_USER;
+       namespaces[1] = EXTATTR_NAMESPACE_SYSTEM;
+
+       for (i = 0; i < 2; i++) {
+               res = setup_xattrs_namespace(a, entry, fd,
+                   namespaces[i]);
+               switch (res) {
+                       case (ARCHIVE_OK):
+                       case (ARCHIVE_WARN):
+                               break;
+                       default:
+                               return (res);
+               }
+       }
+
+       return (ARCHIVE_OK);
+}
+
 #else
 
 /*
index 52fec7b..2898206 100644 (file)
@@ -1658,7 +1658,7 @@ static int
 setup_current_filesystem(struct archive_read_disk *a)
 {
        struct tree *t = a->tree;
-       struct statvfs sfs;
+       struct statvfs svfs;
        int r, xr = 0;
 
        t->current_filesystem->synthetic = -1;
@@ -1667,16 +1667,16 @@ setup_current_filesystem(struct archive_read_disk *a)
                return (ARCHIVE_FAILED);
        }
        if (tree_current_is_symblic_link_target(t)) {
-               r = statvfs(tree_current_access_path(t), &sfs);
+               r = statvfs(tree_current_access_path(t), &svfs);
                if (r == 0)
                        xr = get_xfer_size(t, -1, tree_current_access_path(t));
        } else {
 #ifdef HAVE_FSTATVFS
-               r = fstatvfs(tree_current_dir_fd(t), &sfs);
+               r = fstatvfs(tree_current_dir_fd(t), &svfs);
                if (r == 0)
                        xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
 #else
-               r = statvfs(".", &sfs);
+               r = statvfs(".", &svfs);
                if (r == 0)
                        xr = get_xfer_size(t, -1, ".");
 #endif
@@ -1688,30 +1688,30 @@ setup_current_filesystem(struct archive_read_disk *a)
        } else if (xr == 1) {
                /* Usually come here unless NetBSD supports _PC_REC_XFER_ALIGN
                 * for pathconf() function. */
-               t->current_filesystem->xfer_align = sfs.f_frsize;
+               t->current_filesystem->xfer_align = svfs.f_frsize;
                t->current_filesystem->max_xfer_size = -1;
 #if defined(HAVE_STRUCT_STATVFS_F_IOSIZE)
-               t->current_filesystem->min_xfer_size = sfs.f_iosize;
-               t->current_filesystem->incr_xfer_size = sfs.f_iosize;
+               t->current_filesystem->min_xfer_size = svfs.f_iosize;
+               t->current_filesystem->incr_xfer_size = svfs.f_iosize;
 #else
-               t->current_filesystem->min_xfer_size = sfs.f_bsize;
-               t->current_filesystem->incr_xfer_size = sfs.f_bsize;
+               t->current_filesystem->min_xfer_size = svfs.f_bsize;
+               t->current_filesystem->incr_xfer_size = svfs.f_bsize;
 #endif
        }
-       if (sfs.f_flag & ST_LOCAL)
+       if (svfs.f_flag & ST_LOCAL)
                t->current_filesystem->remote = 0;
        else
                t->current_filesystem->remote = 1;
 
 #if defined(ST_NOATIME)
-       if (sfs.f_flag & ST_NOATIME)
+       if (svfs.f_flag & ST_NOATIME)
                t->current_filesystem->noatime = 1;
        else
 #endif
                t->current_filesystem->noatime = 0;
 
        /* Set maximum filename length. */
-       t->current_filesystem->name_max = sfs.f_namemax;
+       t->current_filesystem->name_max = svfs.f_namemax;
        return (ARCHIVE_OK);
 }
 
@@ -1840,7 +1840,7 @@ setup_current_filesystem(struct archive_read_disk *a)
 #if defined(HAVE_STATVFS)
        if (svfs.f_flag & ST_NOATIME)
 #else
-       if (sfs.f_flag & ST_NOATIME)
+       if (sfs.f_flags & ST_NOATIME)
 #endif
                t->current_filesystem->noatime = 1;
        else
@@ -1864,7 +1864,7 @@ static int
 setup_current_filesystem(struct archive_read_disk *a)
 {
        struct tree *t = a->tree;
-       struct statvfs sfs;
+       struct statvfs svfs;
        int r, xr = 0;
 
        t->current_filesystem->synthetic = -1;/* Not supported */
@@ -1883,7 +1883,7 @@ setup_current_filesystem(struct archive_read_disk *a)
                            "openat failed");
                        return (ARCHIVE_FAILED);
                }
-               r = fstatvfs(fd, &sfs);
+               r = fstatvfs(fd, &svfs);
                if (r == 0)
                        xr = get_xfer_size(t, fd, NULL);
                close(fd);
@@ -1892,13 +1892,13 @@ setup_current_filesystem(struct archive_read_disk *a)
                        archive_set_error(&a->archive, errno, "fchdir failed");
                        return (ARCHIVE_FAILED);
                }
-               r = statvfs(tree_current_access_path(t), &sfs);
+               r = statvfs(tree_current_access_path(t), &svfs);
                if (r == 0)
                        xr = get_xfer_size(t, -1, tree_current_access_path(t));
 #endif
        } else {
 #ifdef HAVE_FSTATVFS
-               r = fstatvfs(tree_current_dir_fd(t), &sfs);
+               r = fstatvfs(tree_current_dir_fd(t), &svfs);
                if (r == 0)
                        xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
 #else
@@ -1906,7 +1906,7 @@ setup_current_filesystem(struct archive_read_disk *a)
                        archive_set_error(&a->archive, errno, "fchdir failed");
                        return (ARCHIVE_FAILED);
                }
-               r = statvfs(".", &sfs);
+               r = statvfs(".", &svfs);
                if (r == 0)
                        xr = get_xfer_size(t, -1, ".");
 #endif
@@ -1918,14 +1918,14 @@ setup_current_filesystem(struct archive_read_disk *a)
                return (ARCHIVE_FAILED);
        } else if (xr == 1) {
                /* pathconf(_PC_REX_*) operations are not supported. */
-               t->current_filesystem->xfer_align = sfs.f_frsize;
+               t->current_filesystem->xfer_align = svfs.f_frsize;
                t->current_filesystem->max_xfer_size = -1;
-               t->current_filesystem->min_xfer_size = sfs.f_bsize;
-               t->current_filesystem->incr_xfer_size = sfs.f_bsize;
+               t->current_filesystem->min_xfer_size = svfs.f_bsize;
+               t->current_filesystem->incr_xfer_size = svfs.f_bsize;
        }
 
 #if defined(ST_NOATIME)
-       if (sfs.f_flag & ST_NOATIME)
+       if (svfs.f_flag & ST_NOATIME)
                t->current_filesystem->noatime = 1;
        else
 #endif
@@ -1933,7 +1933,7 @@ setup_current_filesystem(struct archive_read_disk *a)
 
 #if defined(USE_READDIR_R)
        /* Set maximum filename length. */
-       t->current_filesystem->name_max = sfs.f_namemax;
+       t->current_filesystem->name_max = svfs.f_namemax;
 #endif
        return (ARCHIVE_OK);
 }
index 1ba5fcb..4f5c351 100644 (file)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd August 14, 2014
+.Dd June 9, 2020
 .Dt ARCHIVE_READ_FILTER 3
 .Os
 .Sh NAME
@@ -50,6 +50,8 @@ Streaming Archive Library (libarchive, -larchive)
 .Ft int
 .Fn archive_read_support_filter_all "struct archive *"
 .Ft int
+.Fn archive_read_support_filter_by_code "struct archive *" "int"
+.Ft int
 .Fn archive_read_support_filter_bzip2 "struct archive *"
 .Ft int
 .Fn archive_read_support_filter_compress "struct archive *"
@@ -116,6 +118,14 @@ Note that
 is always enabled by default.
 .It Fn archive_read_support_filter_all
 Enables all available decompression filters.
+.It Fn archive_read_support_filter_by_code
+Enables a single filter specified by the filter code.
+This function does not work with
+.Cm ARCHIVE_FILTER_PROGRAM .
+Note: In statically-linked executables, this will cause
+your program to include support for every filter.
+If executable size is a concern, you may wish to avoid
+using this function.
 .It Fn archive_read_support_filter_program
 Data is fed through the specified external program before being dearchived.
 Note that this disables automatic detection of the compression format,
index 86635e2..561289b 100644 (file)
@@ -221,7 +221,9 @@ file_open(struct archive *a, void *client_data)
        struct read_file_data *mine = (struct read_file_data *)client_data;
        void *buffer;
        const char *filename = NULL;
+#if defined(_WIN32) && !defined(__CYGWIN__)
        const wchar_t *wfilename = NULL;
+#endif
        int fd = -1;
        int is_disk_like = 0;
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -281,10 +283,12 @@ file_open(struct archive *a, void *client_data)
 #endif
        }
        if (fstat(fd, &st) != 0) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
                if (mine->filename_type == FNT_WCS)
                        archive_set_error(a, errno, "Can't stat '%S'",
                            wfilename);
                else
+#endif
                        archive_set_error(a, errno, "Can't stat '%s'",
                            filename);
                goto fail;
index 1d3e49d..796dcdc 100644 (file)
@@ -61,6 +61,9 @@ archive_read_set_format(struct archive *_a, int code)
     case ARCHIVE_FORMAT_CPIO:
       strcpy(str, "cpio");
       break;
+    case ARCHIVE_FORMAT_EMPTY:
+      strcpy(str, "empty");
+      break;
     case ARCHIVE_FORMAT_ISO9660:
       strcpy(str, "iso9660");
       break;
@@ -76,9 +79,15 @@ archive_read_set_format(struct archive *_a, int code)
     case ARCHIVE_FORMAT_RAR_V5:
       strcpy(str, "rar5");
       break;
+    case ARCHIVE_FORMAT_RAW:
+      strcpy(str, "raw");
+      break;
     case ARCHIVE_FORMAT_TAR:
       strcpy(str, "tar");
       break;
+    case ARCHIVE_FORMAT_WARC:
+      strcpy(str, "warc");
+      break;
     case ARCHIVE_FORMAT_XAR:
       strcpy(str, "xar");
       break;
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_by_code.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_by_code.c
new file mode 100644 (file)
index 0000000..94c4af6
--- /dev/null
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2020 Martin Matuska
+ * 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(S) ``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(S) 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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive.h"
+#include "archive_private.h"
+
+int
+archive_read_support_filter_by_code(struct archive *a, int filter_code)
+{
+       archive_check_magic(a, ARCHIVE_READ_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_read_support_filter_by_code");
+
+       switch (filter_code) {
+       case ARCHIVE_FILTER_NONE:
+               return archive_read_support_filter_none(a);
+               break;
+       case ARCHIVE_FILTER_GZIP:
+               return archive_read_support_filter_gzip(a);
+               break;
+       case ARCHIVE_FILTER_BZIP2:
+               return archive_read_support_filter_bzip2(a);
+               break;
+       case ARCHIVE_FILTER_COMPRESS:
+               return archive_read_support_filter_compress(a);
+               break;
+       case ARCHIVE_FILTER_LZMA:
+               return archive_read_support_filter_lzma(a);
+               break;
+       case ARCHIVE_FILTER_XZ:
+               return archive_read_support_filter_xz(a);
+               break;
+       case ARCHIVE_FILTER_UU:
+               return archive_read_support_filter_uu(a);
+               break;
+       case ARCHIVE_FILTER_RPM:
+               return archive_read_support_filter_rpm(a);
+               break;
+       case ARCHIVE_FILTER_LZIP:
+               return archive_read_support_filter_lzip(a);
+               break;
+       case ARCHIVE_FILTER_LRZIP:
+               return archive_read_support_filter_lrzip(a);
+               break;
+       case ARCHIVE_FILTER_LZOP:
+               return archive_read_support_filter_lzop(a);
+               break;
+       case ARCHIVE_FILTER_GRZIP:
+               return archive_read_support_filter_grzip(a);
+               break;
+       case ARCHIVE_FILTER_LZ4:
+               return archive_read_support_filter_lz4(a);
+               break;
+       case ARCHIVE_FILTER_ZSTD:
+               return archive_read_support_filter_zstd(a);
+               break;
+       }
+       return (ARCHIVE_FATAL);
+}
index b8bf128..bf5b6f2 100644 (file)
@@ -400,7 +400,7 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
        static const size_t out_buf_len = 65536;
        char *out_buf;
        const char *prefix = "Program: ";
-       pid_t child;
+       int ret;
        size_t l;
 
        l = strlen(prefix) + strlen(cmd) + 1;
@@ -426,9 +426,9 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
        state->out_buf = out_buf;
        state->out_buf_len = out_buf_len;
 
-       child = __archive_create_child(cmd, &state->child_stdin,
-           &state->child_stdout);
-       if (child == -1) {
+       ret = __archive_create_child(cmd, &state->child_stdin,
+           &state->child_stdout, &state->child);
+       if (ret != ARCHIVE_OK) {
                free(state->out_buf);
                archive_string_free(&state->description);
                free(state);
@@ -437,21 +437,6 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
                    cmd);
                return (ARCHIVE_FATAL);
        }
-#if defined(_WIN32) && !defined(__CYGWIN__)
-       state->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child);
-       if (state->child == NULL) {
-               child_stop(self, state);
-               free(state->out_buf);
-               archive_string_free(&state->description);
-               free(state);
-               archive_set_error(&self->archive->archive, EINVAL,
-                   "Can't initialize filter; unable to run program \"%s\"",
-                   cmd);
-               return (ARCHIVE_FATAL);
-       }
-#else
-       state->child = child;
-#endif
 
        self->data = state;
        self->read = program_filter_read;
index e1ec60e..c4e8ec7 100644 (file)
@@ -119,6 +119,8 @@ zstd_bidder_bid(struct archive_read_filter_bidder *self,
 
        /* Zstd frame magic values */
        const unsigned zstd_magic = 0xFD2FB528U;
+       const unsigned zstd_magic_skippable_start = 0x184D2A50U;
+       const unsigned zstd_magic_skippable_mask = 0xFFFFFFF0;
 
        (void) self; /* UNUSED */
 
@@ -129,6 +131,8 @@ zstd_bidder_bid(struct archive_read_filter_bidder *self,
        prefix = archive_le32dec(buffer);
        if (prefix == zstd_magic)
                return (32);
+       if ((prefix & zstd_magic_skippable_mask) == zstd_magic_skippable_start)
+               return (32);
 
        return (0);
 }
index 034353d..89e96f1 100644 (file)
 #include "archive_platform.h"
 __FBSDID("$FreeBSD$");
 
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
 #include "archive.h"
 #include "archive_private.h"
 
@@ -48,6 +52,9 @@ archive_read_support_format_by_code(struct archive *a, int format_code)
        case ARCHIVE_FORMAT_CPIO:
                return archive_read_support_format_cpio(a);
                break;
+       case ARCHIVE_FORMAT_EMPTY:
+               return archive_read_support_format_empty(a);
+               break;
        case ARCHIVE_FORMAT_ISO9660:
                return archive_read_support_format_iso9660(a);
                break;
@@ -63,9 +70,15 @@ archive_read_support_format_by_code(struct archive *a, int format_code)
        case ARCHIVE_FORMAT_RAR_V5:
                return archive_read_support_format_rar5(a);
                break;
+       case ARCHIVE_FORMAT_RAW:
+               return archive_read_support_format_raw(a);
+               break;
        case ARCHIVE_FORMAT_TAR:
                return archive_read_support_format_tar(a);
                break;
+       case ARCHIVE_FORMAT_WARC:
+               return archive_read_support_format_warc(a);
+               break;
        case ARCHIVE_FORMAT_XAR:
                return archive_read_support_format_xar(a);
                break;
@@ -73,5 +86,7 @@ archive_read_support_format_by_code(struct archive *a, int format_code)
                return archive_read_support_format_zip(a);
                break;
        }
+       archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+           "Invalid format code specified");
        return (ARCHIVE_FATAL);
 }
index 58644ba..57547d4 100644 (file)
@@ -1172,7 +1172,7 @@ cab_checksum_finish(struct archive_read *a)
            cfdata->memimage + CFDATA_cbData, l, cfdata->sum_calculated);
        if (cfdata->sum_calculated != cfdata->sum) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                   "Checksum error CFDATA[%d] %x:%x in %d bytes",
+                   "Checksum error CFDATA[%d] %" PRIx32 ":%" PRIx32 " in %d bytes",
                    cab->entry_cffolder->cfdata_index -1,
                    cfdata->sum, cfdata->sum_calculated,
                    cfdata->compressed_size);
index c641eb9..53fb6cc 100644 (file)
@@ -47,7 +47,7 @@ archive_read_support_format_empty(struct archive *_a)
 
        r = __archive_read_register_format(a,
            NULL,
-           NULL,
+           "empty",
            archive_read_format_empty_bid,
            NULL,
            archive_read_format_empty_read_header,
index 332944a..93ba295 100644 (file)
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011
 
 #include "archive.h"
 #include "archive_entry.h"
+#include "archive_entry_private.h"
 #include "archive_private.h"
 #include "archive_rb.h"
 #include "archive_read_private.h"
@@ -135,6 +136,9 @@ static int  skip(struct archive_read *a);
 static int     read_header(struct archive_read *,
                    struct archive_entry *);
 static int64_t mtree_atol(char **, int base);
+#ifndef HAVE_STRNLEN
+static size_t  mtree_strnlen(const char *, size_t);
+#endif
 
 /*
  * There's no standard for TIME_T_MAX/TIME_T_MIN.  So we compute them
@@ -186,6 +190,24 @@ get_time_t_min(void)
 #endif
 }
 
+#ifdef HAVE_STRNLEN
+#define mtree_strnlen(a,b) strnlen(a,b)
+#else
+static size_t
+mtree_strnlen(const char *p, size_t maxlen)
+{
+       size_t i;
+
+       for (i = 0; i <= maxlen; i++) {
+               if (p[i] == 0)
+                       break;
+       }
+       if (i > maxlen)
+               return (-1);/* invalid */
+       return (i);
+}
+#endif
+
 static int
 archive_read_format_mtree_options(struct archive_read *a,
     const char *key, const char *val)
@@ -1482,6 +1504,84 @@ parse_device(dev_t *pdev, struct archive *a, char *val)
 #undef MAX_PACK_ARGS
 }
 
+static int
+parse_hex_nibble(char c)
+{
+       if (c >= '0' && c <= '9')
+               return c - '0';
+       if (c >= 'a' && c <= 'f')
+               return 10 + c - 'a';
+#if 0
+       /* XXX: Is uppercase something we should support? */
+       if (c >= 'A' && c <= 'F')
+               return 10 + c - 'A';
+#endif
+
+       return -1;
+}
+
+static int
+parse_digest(struct archive_read *a, struct archive_entry *entry,
+    const char *digest, int type)
+{
+       unsigned char digest_buf[64];
+       int high, low;
+       size_t i, j, len;
+
+       switch (type) {
+       case ARCHIVE_ENTRY_DIGEST_MD5:
+               len = sizeof(entry->digest.md5);
+               break;
+       case ARCHIVE_ENTRY_DIGEST_RMD160:
+               len = sizeof(entry->digest.rmd160);
+               break;
+       case ARCHIVE_ENTRY_DIGEST_SHA1:
+               len = sizeof(entry->digest.sha1);
+               break;
+       case ARCHIVE_ENTRY_DIGEST_SHA256:
+               len = sizeof(entry->digest.sha256);
+               break;
+       case ARCHIVE_ENTRY_DIGEST_SHA384:
+               len = sizeof(entry->digest.sha384);
+               break;
+       case ARCHIVE_ENTRY_DIGEST_SHA512:
+               len = sizeof(entry->digest.sha512);
+               break;
+       default:
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+                       "Internal error: Unknown digest type");
+               return ARCHIVE_FATAL;
+       }
+
+       if (len > sizeof(digest_buf)) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+                       "Internal error: Digest storage too large");
+               return ARCHIVE_FATAL;
+       }
+
+       len *= 2;
+
+       if (mtree_strnlen(digest, len+1) != len) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                                 "incorrect digest length, ignoring");
+               return ARCHIVE_WARN;
+       }
+
+       for (i = 0, j = 0; i < len; i += 2, j++) {
+               high = parse_hex_nibble(digest[i]);
+               low = parse_hex_nibble(digest[i+1]);
+               if (high == -1 || low == -1) {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                                         "invalid digest data, ignoring");
+                       return ARCHIVE_WARN;
+               }
+
+               digest_buf[j] = high << 4 | low;
+       }
+
+       return archive_entry_set_digest(entry, type, digest_buf);
+}
+
 /*
  * Parse a single keyword and its value.
  */
@@ -1580,8 +1680,10 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
                }
                __LA_FALLTHROUGH;
        case 'm':
-               if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0)
-                       break;
+               if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) {
+                       return parse_digest(a, entry, val,
+                           ARCHIVE_ENTRY_DIGEST_MD5);
+               }
                if (strcmp(key, "mode") == 0) {
                        if (val[0] >= '0' && val[0] <= '7') {
                                *parsed_kws |= MTREE_HAS_PERM;
@@ -1617,21 +1719,32 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
                        return r;
                }
                if (strcmp(key, "rmd160") == 0 ||
-                   strcmp(key, "rmd160digest") == 0)
-                       break;
+                   strcmp(key, "rmd160digest") == 0) {
+                       return parse_digest(a, entry, val,
+                           ARCHIVE_ENTRY_DIGEST_RMD160);
+               }
                __LA_FALLTHROUGH;
        case 's':
-               if (strcmp(key, "sha1") == 0 || strcmp(key, "sha1digest") == 0)
-                       break;
+               if (strcmp(key, "sha1") == 0 ||
+                   strcmp(key, "sha1digest") == 0) {
+                       return parse_digest(a, entry, val,
+                           ARCHIVE_ENTRY_DIGEST_SHA1);
+               }
                if (strcmp(key, "sha256") == 0 ||
-                   strcmp(key, "sha256digest") == 0)
-                       break;
+                   strcmp(key, "sha256digest") == 0) {
+                       return parse_digest(a, entry, val,
+                           ARCHIVE_ENTRY_DIGEST_SHA256);
+               }
                if (strcmp(key, "sha384") == 0 ||
-                   strcmp(key, "sha384digest") == 0)
-                       break;
+                   strcmp(key, "sha384digest") == 0) {
+                       return parse_digest(a, entry, val,
+                           ARCHIVE_ENTRY_DIGEST_SHA384);
+               }
                if (strcmp(key, "sha512") == 0 ||
-                   strcmp(key, "sha512digest") == 0)
-                       break;
+                   strcmp(key, "sha512digest") == 0) {
+                       return parse_digest(a, entry, val,
+                           ARCHIVE_ENTRY_DIGEST_SHA512);
+               }
                if (strcmp(key, "size") == 0) {
                        archive_entry_set_size(entry, mtree_atol(&val, 10));
                        break;
index 61f2330..6dca350 100644 (file)
 #undef minimum
 #define minimum(a, b)  ((a)<(b)?(a):(b))
 
+/* Stack overflow check */
+#define MAX_COMPRESS_DEPTH 1024
+
 /* Fields common to all headers */
 struct rar_header
 {
@@ -340,7 +343,7 @@ static int read_symlink_stored(struct archive_read *, struct archive_entry *,
 static int read_data_stored(struct archive_read *, const void **, size_t *,
                             int64_t *);
 static int read_data_compressed(struct archive_read *, const void **, size_t *,
-                          int64_t *);
+                          int64_t *, size_t);
 static int rar_br_preparation(struct archive_read *, struct rar_br *);
 static int parse_codes(struct archive_read *);
 static void free_codes(struct archive_read *);
@@ -1026,7 +1029,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
   case COMPRESS_METHOD_NORMAL:
   case COMPRESS_METHOD_GOOD:
   case COMPRESS_METHOD_BEST:
-    ret = read_data_compressed(a, buff, size, offset);
+    ret = read_data_compressed(a, buff, size, offset, 0);
     if (ret != ARCHIVE_OK && ret != ARCHIVE_WARN) {
       __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);
       rar->start_new_table = 1;
@@ -1883,8 +1886,11 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
 
 static int
 read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
-               int64_t *offset)
+               int64_t *offset, size_t looper)
 {
+  if (looper++ > MAX_COMPRESS_DEPTH)
+    return (ARCHIVE_FATAL);
+
   struct rar *rar;
   int64_t start, end, actualend;
   size_t bs;
@@ -1982,7 +1988,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
         {
           case 0:
             rar->start_new_table = 1;
-            return read_data_compressed(a, buff, size, offset);
+            return read_data_compressed(a, buff, size, offset, looper);
 
           case 2:
             rar->ppmd_eod = 1;/* End Of ppmd Data. */
index d3a1c1b..3131955 100644 (file)
@@ -3084,12 +3084,6 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
 
                        continue;
                }
-
-               /* The program counter shouldn't reach here. */
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                   "Unsupported block code: 0x%x", num);
-
-               return ARCHIVE_FATAL;
        }
 
        return ARCHIVE_OK;
@@ -3837,7 +3831,7 @@ static int verify_checksums(struct archive_read* a) {
 
                                DEBUG_CODE {
                                        printf("Checksum error: CRC32 "
-                                           "(was: %08x, expected: %08x)\n",
+                                           "(was: %08" PRIx32 ", expected: %08" PRIx32 ")\n",
                                            rar->file.calculated_crc32,
                                            rar->file.stored_crc32);
                                }
@@ -3851,7 +3845,7 @@ static int verify_checksums(struct archive_read* a) {
                        } else {
                                DEBUG_CODE {
                                        printf("Checksum OK: CRC32 "
-                                           "(%08x/%08x)\n",
+                                           "(%08" PRIx32 "/%08" PRIx32 ")\n",
                                            rar->file.stored_crc32,
                                            rar->file.calculated_crc32);
                                }
@@ -3912,6 +3906,9 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
        int ret;
        struct rar5* rar = get_context(a);
 
+       if (size)
+               *size = 0;
+
        if(rar->file.dir > 0) {
                /* Don't process any data if this file entry was declared
                 * as a directory. This is needed, because entries marked as
index c63d46f..96d8101 100644 (file)
@@ -1797,6 +1797,16 @@ pax_attribute_schily_xattr(struct archive_entry *entry,
 }
 
 static int
+pax_attribute_rht_security_selinux(struct archive_entry *entry,
+       const char *value, size_t value_length)
+{
+       archive_entry_xattr_add_entry(entry, "security.selinux",
+            value, value_length);
+
+       return 0;
+}
+
+static int
 pax_attribute_acl(struct archive_read *a, struct tar *tar,
     struct archive_entry *entry, const char *value, int type)
 {
@@ -1966,6 +1976,14 @@ pax_attribute(struct archive_read *a, struct tar *tar,
                if (memcmp(key, "LIBARCHIVE.xattr.", 17) == 0)
                        pax_attribute_xattr(entry, key, value);
                break;
+       case 'R':
+               /* GNU tar uses RHT.security header to store SELinux xattrs
+                * SCHILY.xattr.security.selinux == RHT.security.selinux */
+               if (strcmp(key, "RHT.security.selinux") == 0) {
+                       pax_attribute_rht_security_selinux(entry, value,
+                           value_length);
+                       }
+               break;
        case 'S':
                /* We support some keys used by the "star" archiver */
                if (strcmp(key, "SCHILY.acl.access") == 0) {
index 72977b8..2732996 100644 (file)
@@ -127,7 +127,7 @@ static int _warc_skip(struct archive_read *a);
 static int _warc_rdhdr(struct archive_read *a, struct archive_entry *e);
 
 /* private routines */
-static unsigned int _warc_rdver(const char buf[10], size_t bsz);
+static unsigned int _warc_rdver(const char *buf, size_t bsz);
 static unsigned int _warc_rdtyp(const char *buf, size_t bsz);
 static warc_string_t _warc_rduri(const char *buf, size_t bsz);
 static ssize_t _warc_rdlen(const char *buf, size_t bsz);
@@ -337,6 +337,14 @@ start_over:
                        mtime = rtime;
                }
                break;
+       case WT_NONE:
+       case WT_INFO:
+       case WT_META:
+       case WT_REQ:
+       case WT_RVIS:
+       case WT_CONV:
+       case WT_CONT:
+       case LAST_WT:
        default:
                fnam.len = 0U;
                fnam.str = NULL;
@@ -361,6 +369,14 @@ start_over:
                        break;
                }
                /* FALLTHROUGH */
+       case WT_NONE:
+       case WT_INFO:
+       case WT_META:
+       case WT_REQ:
+       case WT_RVIS:
+       case WT_CONV:
+       case WT_CONT:
+       case LAST_WT:
        default:
                /* consume the content and start over */
                _warc_skip(a);
@@ -427,7 +443,7 @@ _warc_skip(struct archive_read *a)
 static void*
 deconst(const void *c)
 {
-       return (char *)0x1 + (((const char *)c) - (const char *)0x1);
+       return (void *)(uintptr_t)c;
 }
 
 static char*
index 9489e51..2e60cf7 100644 (file)
@@ -36,7 +36,7 @@ __FBSDID("$FreeBSD$");
 #elif HAVE_BSDXML_H
 #include <bsdxml.h>
 #elif HAVE_EXPAT_H
-#include <expat.h>
+#include <cm3p/expat.h>
 #endif
 #ifdef HAVE_BZLIB_H
 #include <cm3p/bzlib.h>
@@ -458,6 +458,11 @@ archive_read_support_format_xar(struct archive *_a)
                return (ARCHIVE_FATAL);
        }
 
+       /* initialize xar->file_queue */
+       xar->file_queue.allocated = 0;
+       xar->file_queue.used = 0;
+       xar->file_queue.files = NULL;
+
        r = __archive_read_register_format(a,
            xar,
            "xar",
@@ -1221,10 +1226,12 @@ heap_add_entry(struct archive_read *a,
        /* Expand our pending files list as necessary. */
        if (heap->used >= heap->allocated) {
                struct xar_file **new_pending_files;
-               int new_size = heap->allocated * 2;
+               int new_size;
 
                if (heap->allocated < 1024)
                        new_size = 1024;
+               else
+                       new_size = heap->allocated * 2;
                /* Overflow might keep us from growing the list. */
                if (new_size <= heap->allocated) {
                        archive_set_error(&a->archive,
@@ -1238,9 +1245,11 @@ heap_add_entry(struct archive_read *a,
                            ENOMEM, "Out of memory");
                        return (ARCHIVE_FATAL);
                }
-               memcpy(new_pending_files, heap->files,
-                   heap->allocated * sizeof(new_pending_files[0]));
-               free(heap->files);
+               if (heap->allocated) {
+                       memcpy(new_pending_files, heap->files,
+                           heap->allocated * sizeof(new_pending_files[0]));
+                       free(heap->files);
+               }
                heap->files = new_pending_files;
                heap->allocated = new_size;
        }
index 4d71f98..6314c68 100644 (file)
@@ -53,10 +53,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_zip.c 201102
 #include <cm3p/zlib.h>
 #endif
 #ifdef HAVE_BZLIB_H
-#include <bzlib.h>
+#include <cm3p/bzlib.h>
 #endif
 #ifdef HAVE_LZMA_H
-#include <lzma.h>
+#include <cm3p/lzma.h>
 #endif
 
 #include "archive.h"
@@ -899,6 +899,81 @@ process_extra(struct archive_read *a, struct archive_entry *entry,
        return ARCHIVE_OK;
 }
 
+#if HAVE_LZMA_H && HAVE_LIBLZMA
+/*
+ * Auxiliary function to uncompress data chunk from zipx archive
+ * (zip with lzma compression).
+ */
+static int
+zipx_lzma_uncompress_buffer(const char *compressed_buffer,
+       size_t compressed_buffer_size,
+       char *uncompressed_buffer,
+       size_t uncompressed_buffer_size)
+{
+       int status = ARCHIVE_FATAL;
+       // length of 'lzma properties data' in lzma compressed
+       // data segment (stream) inside zip archive
+       const size_t lzma_params_length = 5;
+       // offset of 'lzma properties data' from the beginning of lzma stream
+       const size_t lzma_params_offset = 4;
+       // end position of 'lzma properties data' in lzma stream
+       const size_t lzma_params_end = lzma_params_offset + lzma_params_length;
+       if (compressed_buffer == NULL ||
+                       compressed_buffer_size < lzma_params_end ||
+                       uncompressed_buffer == NULL)
+               return status;
+
+       // prepare header for lzma_alone_decoder to replace zipx header
+       // (see comments in 'zipx_lzma_alone_init' for justification)
+#pragma pack(push)
+#pragma pack(1)
+       struct _alone_header
+       {
+               uint8_t bytes[5]; // lzma_params_length
+               uint64_t uncompressed_size;
+       } alone_header;
+#pragma pack(pop)
+       // copy 'lzma properties data' blob
+       memcpy(&alone_header.bytes[0], compressed_buffer + lzma_params_offset,
+               lzma_params_length);
+       alone_header.uncompressed_size = UINT64_MAX;
+
+       // prepare new compressed buffer, see 'zipx_lzma_alone_init' for details
+       const size_t lzma_alone_buffer_size =
+               compressed_buffer_size - lzma_params_end + sizeof(alone_header);
+       unsigned char *lzma_alone_compressed_buffer =
+               (unsigned char*) malloc(lzma_alone_buffer_size);
+       if (lzma_alone_compressed_buffer == NULL)
+               return status;
+       // copy lzma_alone header into new buffer
+       memcpy(lzma_alone_compressed_buffer, (void*) &alone_header,
+               sizeof(alone_header));
+       // copy compressed data into new buffer
+       memcpy(lzma_alone_compressed_buffer + sizeof(alone_header),
+               compressed_buffer + lzma_params_end,
+               compressed_buffer_size - lzma_params_end);
+
+       // create and fill in lzma_alone_decoder stream
+       lzma_stream stream = LZMA_STREAM_INIT;
+       lzma_ret ret = lzma_alone_decoder(&stream, UINT64_MAX);
+       if (ret == LZMA_OK)
+       {
+               stream.next_in = lzma_alone_compressed_buffer;
+               stream.avail_in = lzma_alone_buffer_size;
+               stream.total_in = 0;
+               stream.next_out = (unsigned char*)uncompressed_buffer;
+               stream.avail_out = uncompressed_buffer_size;
+               stream.total_out = 0;
+               ret = lzma_code(&stream, LZMA_RUN);
+               if (ret == LZMA_OK || ret == LZMA_STREAM_END)
+                       status = ARCHIVE_OK;
+       }
+       lzma_end(&stream);
+       free(lzma_alone_compressed_buffer);
+       return status;
+}
+#endif
+
 /*
  * Assumes file pointer is at beginning of local file header.
  */
@@ -1173,18 +1248,64 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
                            "Truncated Zip file");
                        return ARCHIVE_FATAL;
                }
+               // take into account link compression if any
+               size_t linkname_full_length = linkname_length;
+               if (zip->entry->compression != 0)
+               {
+                       // symlink target string appeared to be compressed
+                       int status = ARCHIVE_FATAL;
+                       char *uncompressed_buffer =
+                               (char*) malloc(zip_entry->uncompressed_size);
+                       if (uncompressed_buffer == NULL)
+                       {
+                               archive_set_error(&a->archive, ENOMEM,
+                                       "No memory for lzma decompression");
+                               return status;
+                       }
+
+                       switch (zip->entry->compression)
+                       {
+#if HAVE_LZMA_H && HAVE_LIBLZMA
+                               case 14: /* ZIPx LZMA compression. */
+                                       /*(see zip file format specification, section 4.4.5)*/
+                                       status = zipx_lzma_uncompress_buffer(p,
+                                               linkname_length,
+                                               uncompressed_buffer,
+                                               (size_t)zip_entry->uncompressed_size);
+                                       break;
+#endif
+                               default: /* Unsupported compression. */
+                                       break;
+                       }
+                       if (status == ARCHIVE_OK)
+                       {
+                               p = uncompressed_buffer;
+                               linkname_full_length =
+                                       (size_t)zip_entry->uncompressed_size;
+                       }
+                       else
+                       {
+                               archive_set_error(&a->archive,
+                                       ARCHIVE_ERRNO_FILE_FORMAT,
+                                       "Unsupported ZIP compression method "
+                                       "during decompression of link entry (%d: %s)",
+                                       zip->entry->compression,
+                                       compression_name(zip->entry->compression));
+                               return ARCHIVE_FAILED;
+                       }
+               }
 
                sconv = zip->sconv;
                if (sconv == NULL && (zip->entry->zip_flags & ZIP_UTF8_NAME))
                        sconv = zip->sconv_utf8;
                if (sconv == NULL)
                        sconv = zip->sconv_default;
-               if (archive_entry_copy_symlink_l(entry, p, linkname_length,
+               if (archive_entry_copy_symlink_l(entry, p, linkname_full_length,
                    sconv) != 0) {
                        if (errno != ENOMEM && sconv == zip->sconv_utf8 &&
                            (zip->entry->zip_flags & ZIP_UTF8_NAME))
                            archive_entry_copy_symlink_l(entry, p,
-                               linkname_length, NULL);
+                               linkname_full_length, NULL);
                        if (errno == ENOMEM) {
                                archive_set_error(&a->archive, ENOMEM,
                                    "Can't allocate memory for Symlink");
@@ -1901,15 +2022,15 @@ zipx_ppmd8_init(struct archive_read *a, struct zip *zip)
 
        if(order < 2 || restore_method > 2) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                   "Invalid parameter set in PPMd8 stream (order=%d, "
-                   "restore=%d)", order, restore_method);
+                   "Invalid parameter set in PPMd8 stream (order=%" PRId32 ", "
+                   "restore=%" PRId32 ")", order, restore_method);
                return (ARCHIVE_FAILED);
        }
 
        /* Allocate the memory needed to properly decompress the file. */
        if(!__archive_ppmd8_functions.Ppmd8_Alloc(&zip->ppmd8, mem << 20)) {
                archive_set_error(&a->archive, ENOMEM,
-                   "Unable to allocate memory for PPMd8 stream: %d bytes",
+                   "Unable to allocate memory for PPMd8 stream: %" PRId32 " bytes",
                    mem << 20);
                return (ARCHIVE_FATAL);
        }
index c77dcf5..7460ded 100644 (file)
@@ -3881,6 +3881,11 @@ archive_mstring_get_utf8(struct archive *a, struct archive_mstring *aes,
        }
 
        *p = NULL;
+       /* Try converting WCS to MBS first if MBS does not exist yet. */
+       if ((aes->aes_set & AES_SET_MBS) == 0) {
+               const char *pm; /* unused */
+               archive_mstring_get_mbs(a, aes, &pm); /* ignore errors, we'll handle it later */
+       }
        if (aes->aes_set & AES_SET_MBS) {
                sc = archive_string_conversion_to_charset(a, "UTF-8", 1);
                if (sc == NULL)
@@ -3903,9 +3908,9 @@ int
 archive_mstring_get_mbs(struct archive *a, struct archive_mstring *aes,
     const char **p)
 {
+       struct archive_string_conv *sc;
        int r, ret = 0;
 
-       (void)a; /* UNUSED */
        /* If we already have an MBS form, return that immediately. */
        if (aes->aes_set & AES_SET_MBS) {
                *p = aes->aes_mbs.s;
@@ -3926,10 +3931,23 @@ archive_mstring_get_mbs(struct archive *a, struct archive_mstring *aes,
                        ret = -1;
        }
 
-       /*
-        * Only a UTF-8 form cannot avail because its conversion already
-        * failed at archive_mstring_update_utf8().
-        */
+       /* If there's a UTF-8 form, try converting with the native locale. */
+       if (aes->aes_set & AES_SET_UTF8) {
+               archive_string_empty(&(aes->aes_mbs));
+               sc = archive_string_conversion_from_charset(a, "UTF-8", 1);
+               if (sc == NULL)
+                       return (-1);/* Couldn't allocate memory for sc. */
+               r = archive_strncpy_l(&(aes->aes_mbs),
+                       aes->aes_utf8.s, aes->aes_utf8.length, sc);
+               if (a == NULL)
+                       free_sconv_object(sc);
+               *p = aes->aes_mbs.s;
+               if (r == 0) {
+                       aes->aes_set |= AES_SET_MBS;
+                       ret = 0;/* success; overwrite previous error. */
+               } else
+                       ret = -1;/* failure. */
+       }
        return (ret);
 }
 
@@ -3947,6 +3965,11 @@ archive_mstring_get_wcs(struct archive *a, struct archive_mstring *aes,
        }
 
        *wp = NULL;
+       /* Try converting UTF8 to MBS first if MBS does not exist yet. */
+       if ((aes->aes_set & AES_SET_MBS) == 0) {
+               const char *p; /* unused */
+               archive_mstring_get_mbs(a, aes, &p); /* ignore errors, we'll handle it later */
+       }
        /* Try converting MBS to WCS using native locale. */
        if (aes->aes_set & AES_SET_MBS) {
                archive_wstring_empty(&(aes->aes_wcs));
@@ -3962,11 +3985,12 @@ archive_mstring_get_wcs(struct archive *a, struct archive_mstring *aes,
 }
 
 int
-archive_mstring_get_mbs_l(struct archive_mstring *aes,
+archive_mstring_get_mbs_l(struct archive *a, struct archive_mstring *aes,
     const char **p, size_t *length, struct archive_string_conv *sc)
 {
        int r, ret = 0;
 
+       (void)r; /* UNUSED */
 #if defined(_WIN32) && !defined(__CYGWIN__)
        /*
         * Internationalization programming on Windows must use Wide
@@ -3989,20 +4013,12 @@ archive_mstring_get_mbs_l(struct archive_mstring *aes,
        }
 #endif
 
-       /* If there is not an MBS form but is a WCS form, try converting
+       /* If there is not an MBS form but there is a WCS or UTF8 form, try converting
         * with the native locale to be used for translating it to specified
         * character-set. */
-       if ((aes->aes_set & AES_SET_MBS) == 0 &&
-           (aes->aes_set & AES_SET_WCS) != 0) {
-               archive_string_empty(&(aes->aes_mbs));
-               r = archive_string_append_from_wcs(&(aes->aes_mbs),
-                   aes->aes_wcs.s, aes->aes_wcs.length);
-               if (r == 0)
-                       aes->aes_set |= AES_SET_MBS;
-               else if (errno == ENOMEM)
-                       return (-1);
-               else
-                       ret = -1;
+       if ((aes->aes_set & AES_SET_MBS) == 0) {
+               const char *pm; /* unused */
+               archive_mstring_get_mbs(a, aes, &pm); /* ignore errors, we'll handle it later */
        }
        /* If we already have an MBS form, use it to be translated to
         * specified character-set. */
index 27e1ad6..49d7d30 100644 (file)
@@ -226,7 +226,7 @@ void        archive_mstring_copy(struct archive_mstring *dest, struct archive_mstring *
 int archive_mstring_get_mbs(struct archive *, struct archive_mstring *, const char **);
 int archive_mstring_get_utf8(struct archive *, struct archive_mstring *, const char **);
 int archive_mstring_get_wcs(struct archive *, struct archive_mstring *, const wchar_t **);
-int    archive_mstring_get_mbs_l(struct archive_mstring *, const char **,
+int    archive_mstring_get_mbs_l(struct archive *, struct archive_mstring *, const char **,
            size_t *, struct archive_string_conv *);
 int    archive_mstring_copy_mbs(struct archive_mstring *, const char *mbs);
 int    archive_mstring_copy_mbs_len(struct archive_mstring *, const char *mbs,
index 10dca73..83586b5 100644 (file)
@@ -365,6 +365,7 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
                }
                fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
                if (fd == -1) {
+                       la_dosmaperr(GetLastError());
                        CloseHandle(h);
                        goto exit_tmpfile;
                } else
@@ -432,6 +433,11 @@ __archive_mktemp(const char *tmpdir)
                if (temp_name.s[temp_name.length-1] != '/')
                        archive_strappend_char(&temp_name, '/');
        }
+#ifdef O_TMPFILE
+       fd = open(temp_name.s, O_RDWR|O_CLOEXEC|O_TMPFILE|O_EXCL, 0600); 
+       if(fd >= 0)
+               goto exit_tmpfile;
+#endif
        archive_strcat(&temp_name, "libarchive_XXXXXX");
        fd = mkstemp(temp_name.s);
        if (fd < 0)
index 98a55fb..8d70f51 100644 (file)
@@ -456,6 +456,25 @@ archive_write_client_write(struct archive_write_filter *f,
 }
 
 static int
+archive_write_client_free(struct archive_write_filter *f)
+{
+       struct archive_write *a = (struct archive_write *)f->archive;
+
+       if (a->client_freer)
+               (*a->client_freer)(&a->archive, a->client_data);
+       a->client_data = NULL;
+
+       /* Clear passphrase. */
+       if (a->passphrase != NULL) {
+               memset(a->passphrase, 0, strlen(a->passphrase));
+               free(a->passphrase);
+               a->passphrase = NULL;
+       }
+
+       return (ARCHIVE_OK);
+}
+
+static int
 archive_write_client_close(struct archive_write_filter *f)
 {
        struct archive_write *a = (struct archive_write *)f->archive;
@@ -493,13 +512,7 @@ archive_write_client_close(struct archive_write_filter *f)
                (*a->client_closer)(&a->archive, a->client_data);
        free(state->buffer);
        free(state);
-       a->client_data = NULL;
-       /* Clear passphrase. */
-       if (a->passphrase != NULL) {
-               memset(a->passphrase, 0, strlen(a->passphrase));
-               free(a->passphrase);
-               a->passphrase = NULL;
-       }
+
        /* Clear the close handler myself not to be called again. */
        f->state = ARCHIVE_WRITE_FILTER_STATE_CLOSED;
        return (ret);
@@ -509,9 +522,9 @@ archive_write_client_close(struct archive_write_filter *f)
  * Open the archive using the current settings.
  */
 int
-archive_write_open(struct archive *_a, void *client_data,
+archive_write_open2(struct archive *_a, void *client_data,
     archive_open_callback *opener, archive_write_callback *writer,
-    archive_close_callback *closer)
+    archive_close_callback *closer, archive_free_callback *freer)
 {
        struct archive_write *a = (struct archive_write *)_a;
        struct archive_write_filter *client_filter;
@@ -524,12 +537,14 @@ archive_write_open(struct archive *_a, void *client_data,
        a->client_writer = writer;
        a->client_opener = opener;
        a->client_closer = closer;
+       a->client_freer = freer;
        a->client_data = client_data;
 
        client_filter = __archive_write_allocate_filter(_a);
        client_filter->open = archive_write_client_open;
        client_filter->write = archive_write_client_write;
        client_filter->close = archive_write_client_close;
+       client_filter->free = archive_write_client_free;
 
        ret = __archive_write_filters_open(a);
        if (ret < ARCHIVE_WARN) {
@@ -544,6 +559,15 @@ archive_write_open(struct archive *_a, void *client_data,
        return (ret);
 }
 
+int
+archive_write_open(struct archive *_a, void *client_data,
+    archive_open_callback *opener, archive_write_callback *writer,
+    archive_close_callback *closer)
+{
+       return archive_write_open2(_a, client_data, opener, writer,
+           closer, NULL);
+}
+
 /*
  * Close out the archive.
  */
index a4bc1d9..c096e72 100644 (file)
@@ -196,10 +196,6 @@ __archive_write_program_free(struct archive_write_program_data *data)
 {
 
        if (data) {
-#if defined(_WIN32) && !defined(__CYGWIN__)
-               if (data->child)
-                       CloseHandle(data->child);
-#endif
                free(data->program_name);
                free(data->child_buf);
                free(data);
@@ -211,7 +207,7 @@ int
 __archive_write_program_open(struct archive_write_filter *f,
     struct archive_write_program_data *data, const char *cmd)
 {
-       pid_t child;
+       int ret;
 
        if (data->child_buf == NULL) {
                data->child_buf_len = 65536;
@@ -225,27 +221,13 @@ __archive_write_program_open(struct archive_write_filter *f,
                }
        }
 
-       child = __archive_create_child(cmd, &data->child_stdin,
-                   &data->child_stdout);
-       if (child == -1) {
+       ret = __archive_create_child(cmd, &data->child_stdin,
+                   &data->child_stdout, &data->child);
+       if (ret != ARCHIVE_OK) {
                archive_set_error(f->archive, EINVAL,
                    "Can't launch external program: %s", cmd);
                return (ARCHIVE_FATAL);
        }
-#if defined(_WIN32) && !defined(__CYGWIN__)
-       data->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child);
-       if (data->child == NULL) {
-               close(data->child_stdin);
-               data->child_stdin = -1;
-               close(data->child_stdout);
-               data->child_stdout = -1;
-               archive_set_error(f->archive, EINVAL,
-                   "Can't launch external program: %s", cmd);
-               return (ARCHIVE_FATAL);
-       }
-#else
-       data->child = child;
-#endif
        return (ARCHIVE_OK);
 }
 
index d567ac9..00df8da 100644 (file)
@@ -382,8 +382,12 @@ archive_compressor_xz_options(struct archive_write_filter *f,
                    value[1] != '\0')
                        return (ARCHIVE_WARN);
                data->compression_level = value[0] - '0';
+               if (data->compression_level > 9)
+                       data->compression_level = 9;
+#ifdef _AIX
                if (data->compression_level > 6)
                        data->compression_level = 6;
+#endif
                return (ARCHIVE_OK);
        } else if (strcmp(key, "threads") == 0) {
                char *endptr;
index f67b025..6d71628 100644 (file)
@@ -59,6 +59,16 @@ struct private_data {
 #endif
 };
 
+/* If we don't have the library use default range values (zstdcli.c v1.4.0) */
+#define CLEVEL_MIN -99
+#define CLEVEL_STD_MIN 0 /* prior to 1.3.4 and more recent without using --fast */
+#define CLEVEL_DEFAULT 3
+#define CLEVEL_STD_MAX 19 /* without using --ultra */
+#define CLEVEL_MAX 22
+
+#define MINVER_NEGCLEVEL 10304
+#define MINVER_MINCLEVEL 10306
+
 static int archive_compressor_zstd_options(struct archive_write_filter *,
                    const char *, const char *);
 static int archive_compressor_zstd_open(struct archive_write_filter *);
@@ -96,7 +106,7 @@ archive_write_add_filter_zstd(struct archive *_a)
        f->free = &archive_compressor_zstd_free;
        f->code = ARCHIVE_FILTER_ZSTD;
        f->name = "zstd";
-       data->compression_level = 3; /* Default level used by the zstd CLI */
+       data->compression_level = CLEVEL_DEFAULT;
 #if HAVE_ZSTD_H && HAVE_LIBZSTD
        data->cstream = ZSTD_createCStream();
        if (data->cstream == NULL) {
@@ -135,6 +145,31 @@ archive_compressor_zstd_free(struct archive_write_filter *f)
        return (ARCHIVE_OK);
 }
 
+static int string_is_numeric (const char* value)
+{
+       size_t len = strlen(value);
+       size_t i;
+
+       if (len == 0) {
+               return (ARCHIVE_WARN);
+       }
+       else if (len == 1 && !(value[0] >= '0' && value[0] <= '9')) {
+               return (ARCHIVE_WARN);
+       }
+       else if (!(value[0] >= '0' && value[0] <= '9') &&
+                value[0] != '-' && value[0] != '+') {
+               return (ARCHIVE_WARN);
+       }
+
+       for (i = 1; i < len; i++) {
+               if (!(value[i] >= '0' && value[i] <= '9')) {
+                       return (ARCHIVE_WARN);
+               }
+       }
+
+       return (ARCHIVE_OK);
+}
+
 /*
  * Set write options.
  */
@@ -146,12 +181,25 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
 
        if (strcmp(key, "compression-level") == 0) {
                int level = atoi(value);
-#if HAVE_ZSTD_H && HAVE_LIBZSTD
-               if (level < 1 || level > ZSTD_maxCLevel()) {
-#else
                /* If we don't have the library, hard-code the max level */
-               if (level < 1 || level > 22) {
+               int minimum = CLEVEL_MIN;
+               int maximum = CLEVEL_MAX;
+               if (string_is_numeric(value) != ARCHIVE_OK) {
+                       return (ARCHIVE_WARN);
+               }
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
+               maximum = ZSTD_maxCLevel();
+#if ZSTD_VERSION_NUMBER >= MINVER_MINCLEVEL
+               if (ZSTD_versionNumber() >= MINVER_MINCLEVEL) {
+                       minimum = ZSTD_minCLevel();
+               }
+               else
+#endif
+               if (ZSTD_versionNumber() < MINVER_NEGCLEVEL) {
+                       minimum = CLEVEL_STD_MIN;
+               }
 #endif
+               if (level < minimum || level > maximum) {
                        return (ARCHIVE_WARN);
                }
                data->compression_level = level;
@@ -297,7 +345,26 @@ archive_compressor_zstd_open(struct archive_write_filter *f)
        int r;
 
        archive_string_init(&as);
-       archive_string_sprintf(&as, "zstd -%d", data->compression_level);
+       /* --no-check matches library default */
+       archive_strcpy(&as, "zstd --no-check");
+
+       if (data->compression_level < CLEVEL_STD_MIN) {
+               struct archive_string as2;
+               archive_string_init(&as2);
+               archive_string_sprintf(&as2, " --fast=%d", -data->compression_level);
+               archive_string_concat(&as, &as2);
+               archive_string_free(&as2);
+       } else {
+               struct archive_string as2;
+               archive_string_init(&as2);
+               archive_string_sprintf(&as2, " -%d", data->compression_level);
+               archive_string_concat(&as, &as2);
+               archive_string_free(&as2);
+       }
+
+       if (data->compression_level > CLEVEL_STD_MAX) {
+               archive_strcat(&as, " --ultra");
+       }
 
        f->write = archive_compressor_zstd_write;
        r = __archive_write_program_open(f, data->pdata, as.s);
index c4be9b0..2551ebe 100644 (file)
@@ -546,6 +546,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
 {
        struct archive_write_disk *a = (struct archive_write_disk *)_a;
        struct fixup_entry *fe;
+       const char *linkname;
        int ret, r;
 
        archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
@@ -591,6 +592,17 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
                return (ret);
 
        /*
+        * Check if we have a hardlink that points to itself.
+        */
+       linkname = archive_entry_hardlink(a->entry);
+       if (linkname != NULL && strcmp(a->name, linkname) == 0) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                   "Skipping hardlink pointing to itself: %s",
+                   a->name);
+               return (ARCHIVE_WARN);
+       }
+
+       /*
         * Query the umask so we get predictable mode settings.
         * This gets done on every call to _write_header in case the
         * user edits their umask during the extraction for some
@@ -1856,8 +1868,9 @@ finish_metadata:
                if (a->tmpname) {
                        if (rename(a->tmpname, a->name) == -1) {
                                archive_set_error(&a->archive, errno,
-                                   "rename failed");
-                               ret = ARCHIVE_FATAL;
+                                   "Failed to rename temporary file");
+                               ret = ARCHIVE_FAILED;
+                               unlink(a->tmpname);
                        }
                        a->tmpname = NULL;
                }
@@ -2144,8 +2157,11 @@ restore_entry(struct archive_write_disk *a)
                        if ((a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) &&
                            S_ISREG(a->st.st_mode)) {
                                /* Use a temporary file to extract */
-                               if ((a->fd = la_mktemp(a)) == -1)
+                               if ((a->fd = la_mktemp(a)) == -1) {
+                                       archive_set_error(&a->archive, errno,
+                                           "Can't create temporary file");
                                        return ARCHIVE_FAILED;
+                               }
                                a->pst = NULL;
                                en = 0;
                        } else {
@@ -4407,10 +4423,19 @@ set_xattrs(struct archive_write_disk *a)
                        int e;
                        int namespace;
 
+                       namespace = EXTATTR_NAMESPACE_USER;
+
                        if (strncmp(name, "user.", 5) == 0) {
                                /* "user." attributes go to user namespace */
                                name += 5;
                                namespace = EXTATTR_NAMESPACE_USER;
+                       } else if (strncmp(name, "system.", 7) == 0) {
+                               name += 7;
+                               namespace = EXTATTR_NAMESPACE_SYSTEM;
+                               if (!strcmp(name, "nfs4.acl") ||
+                                   !strcmp(name, "posix1e.acl_access") ||
+                                   !strcmp(name, "posix1e.acl_default"))
+                                       continue;
                        } else {
                                /* Other namespaces are unsupported */
                                archive_strcat(&errlist, name);
@@ -4421,8 +4446,29 @@ set_xattrs(struct archive_write_disk *a)
                        }
 
                        if (a->fd >= 0) {
+                               /*
+                                * On FreeBSD, extattr_set_fd does not
+                                * return the same as
+                                * extattr_set_file. It returns zero
+                                * on success, non-zero on failure.
+                                *
+                                * We can detect the failure by
+                                * manually setting errno prior to the
+                                * call and checking after.
+                                *
+                                * If errno remains zero, fake the
+                                * return value by setting e to size.
+                                *
+                                * This is a hack for now until I
+                                * (Shawn Webb) get FreeBSD to fix the
+                                * issue, if that's even possible.
+                                */
+                               errno = 0;
                                e = extattr_set_fd(a->fd, namespace, name,
                                    value, size);
+                               if (e == 0 && errno == 0) {
+                                       e = size;
+                               }
                        } else {
                                e = extattr_set_link(
                                    archive_entry_pathname(entry), namespace,
index 77e36c4..0c60017 100644 (file)
@@ -549,6 +549,8 @@ la_mktemp(struct archive_write_disk *a)
        a->tmpname = a->_tmpname_data.s;
 
        fd = __archive_mkstemp(a->tmpname);
+       if (fd == -1)
+               return -1;
 
        mode = a->mode & 0777 & ~a->user_umask;
        if (la_chmod(a->tmpname, mode) == -1) {
@@ -1281,9 +1283,11 @@ _archive_write_disk_finish_entry(struct archive *_a)
                        /* Windows does not support atomic rename */
                        disk_unlink(a->name);
                        if (_wrename(a->tmpname, a->name) != 0) {
+                               la_dosmaperr(GetLastError());
                                archive_set_error(&a->archive, errno,
-                                   "rename failed");
-                               ret = ARCHIVE_FATAL;
+                                   "Failed to rename temporary file");
+                               ret = ARCHIVE_FAILED;
+                               disk_unlink(a->tmpname);
                        }
                        a->tmpname = NULL;
                }
@@ -1573,12 +1577,17 @@ restore_entry(struct archive_write_disk *a)
                                S_ISREG(st_mode)) {
                                int fd = la_mktemp(a);
 
-                               if (fd == -1)
+                               if (fd == -1) {
+                                       la_dosmaperr(GetLastError());
+                                       archive_set_error(&a->archive, errno,
+                                           "Can't create temporary file");
                                        return (ARCHIVE_FAILED);
+                               }
                                a->fh = (HANDLE)_get_osfhandle(fd);
-                               if (a->fh == INVALID_HANDLE_VALUE)
+                               if (a->fh == INVALID_HANDLE_VALUE) {
+                                       la_dosmaperr(GetLastError());
                                        return (ARCHIVE_FAILED);
-
+                               }
                                a->pst = NULL;
                                en = 0;
                        } else {
index 0129d10..29bffe4 100644 (file)
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 2, 2012
+.Dd November 12, 2020
 .Dt ARCHIVE_WRITE_OPEN 3
 .Os
 .Sh NAME
 .Nm archive_write_open ,
+.Nm archive_write_open2 ,
 .Nm archive_write_open_fd ,
 .Nm archive_write_open_FILE ,
 .Nm archive_write_open_filename ,
@@ -47,6 +48,15 @@ Streaming Archive Library (libarchive, -larchive)
 .Fa "archive_close_callback *"
 .Fc
 .Ft int
+.Fo archive_write_open2
+.Fa "struct archive *"
+.Fa "void *client_data"
+.Fa "archive_open_callback *"
+.Fa "archive_write_callback *"
+.Fa "archive_close_callback *"
+.Fa "archive_free_callback *"
+.Fc
+.Ft int
 .Fn archive_write_open_fd "struct archive *" "int fd"
 .Ft int
 .Fn archive_write_open_FILE "struct archive *" "FILE *file"
@@ -67,6 +77,11 @@ This is the most generic form of this function, which accepts
 pointers to three callback functions which will be invoked by
 the compression layer to write the constructed archive.
 This does not alter the default archive padding.
+.It Fn archive_write_open2
+Same as
+.Fn archive_write_open
+with an additional fourth free callback. This function should be preferred to
+.Fn archive_write_open .
 .It Fn archive_write_open_fd
 A convenience form of
 .Fn archive_write_open
@@ -106,14 +121,14 @@ to a character or block device node, it will disable padding otherwise.
 You can override this by manually invoking
 .Fn archive_write_set_bytes_in_last_block
 before calling
-.Fn archive_write_open .
+.Fn archive_write_open2 .
 The
 .Fn archive_write_open_filename
 function is safe for use with tape drives or other
 block-oriented devices.
 .It Fn archive_write_open_memory
 A convenience form of
-.Fn archive_write_open
+.Fn archive_write_open2
 that accepts a pointer to a block of memory that will receive
 the archive.
 The final
@@ -145,7 +160,7 @@ To use this library, you will need to define and register
 callback functions that will be invoked to write data to the
 resulting archive.
 These functions are registered by calling
-.Fn archive_write_open :
+.Fn archive_write_open2 :
 .Bl -item -offset indent
 .It
 .Ft typedef int
@@ -162,6 +177,8 @@ If the open fails, it should call
 .Fn archive_set_error
 to register an error code and message and return
 .Cm ARCHIVE_FATAL .
+Please note that if open fails, close is not called and resources must be
+freed inside the open callback or with the free callback.
 .Bl -item -offset indent
 .It
 .Ft typedef la_ssize_t
@@ -192,7 +209,8 @@ to register an error code and message and return -1.
 .El
 .Pp
 The close callback is invoked by archive_close when
-the archive processing is complete.
+the archive processing is complete. If the open callback fails, the close
+callback is not invoked.
 The callback should return
 .Cm ARCHIVE_OK
 on success.
@@ -200,7 +218,14 @@ On failure, the callback should invoke
 .Fn archive_set_error
 to register an error code and message and
 return
-.Cm ARCHIVE_FATAL .
+.Bl -item -offset indent
+.It
+.Ft typedef int
+.Fn archive_free_callback "struct archive *" "void *client_data"
+.El
+.Pp
+The free callback is always invoked on archive_free.
+The return code of this callback is not processed.
 .Pp
 Note that if the client-provided write callback function
 returns a non-zero value, that error will be propagated back to the caller
index d5c426c..b8d491f 100644 (file)
@@ -54,7 +54,7 @@ struct write_fd_data {
        int             fd;
 };
 
-static int     file_close(struct archive *, void *);
+static int     file_free(struct archive *, void *);
 static int     file_open(struct archive *, void *);
 static ssize_t file_write(struct archive *, void *, const void *buff, size_t);
 
@@ -72,8 +72,8 @@ archive_write_open_fd(struct archive *a, int fd)
 #if defined(__CYGWIN__) || defined(_WIN32)
        setmode(mine->fd, O_BINARY);
 #endif
-       return (archive_write_open(a, mine,
-                   file_open, file_write, file_close));
+       return (archive_write_open2(a, mine,
+                   file_open, file_write, NULL, file_free));
 }
 
 static int
@@ -134,11 +134,13 @@ file_write(struct archive *a, void *client_data, const void *buff, size_t length
 }
 
 static int
-file_close(struct archive *a, void *client_data)
+file_free(struct archive *a, void *client_data)
 {
        struct write_fd_data    *mine = (struct write_fd_data *)client_data;
 
        (void)a; /* UNUSED */
+       if (mine == NULL)
+               return (ARCHIVE_OK);
        free(mine);
        return (ARCHIVE_OK);
 }
index f6b1412..bf5b55a 100644 (file)
@@ -51,7 +51,7 @@ struct write_FILE_data {
        FILE            *f;
 };
 
-static int     file_close(struct archive *, void *);
+static int     file_free(struct archive *, void *);
 static int     file_open(struct archive *, void *);
 static ssize_t file_write(struct archive *, void *, const void *buff, size_t);
 
@@ -66,8 +66,8 @@ archive_write_open_FILE(struct archive *a, FILE *f)
                return (ARCHIVE_FATAL);
        }
        mine->f = f;
-       return (archive_write_open(a, mine,
-                   file_open, file_write, file_close));
+       return (archive_write_open2(a, mine, file_open, file_write,
+           NULL, file_free));
 }
 
 static int
@@ -99,11 +99,13 @@ file_write(struct archive *a, void *client_data, const void *buff, size_t length
 }
 
 static int
-file_close(struct archive *a, void *client_data)
+file_free(struct archive *a, void *client_data)
 {
        struct write_FILE_data  *mine = client_data;
 
        (void)a; /* UNUSED */
+       if (mine == NULL)
+               return (ARCHIVE_OK);
        free(mine);
        return (ARCHIVE_OK);
 }
index 66e0dfe..9ceefb1 100644 (file)
@@ -62,6 +62,7 @@ struct write_file_data {
 };
 
 static int     file_close(struct archive *, void *);
+static int     file_free(struct archive *, void *);
 static int     file_open(struct archive *, void *);
 static ssize_t file_write(struct archive *, void *, const void *buff, size_t);
 static int     open_filename(struct archive *, int, const void *);
@@ -123,8 +124,8 @@ open_filename(struct archive *a, int mbs_fn, const void *filename)
                return (ARCHIVE_FAILED);
        }
        mine->fd = -1;
-       return (archive_write_open(a, mine,
-               file_open, file_write, file_close));
+       return (archive_write_open2(a, mine,
+                   file_open, file_write, file_close, file_free));
 }
 
 static int
@@ -244,9 +245,25 @@ file_close(struct archive *a, void *client_data)
 
        (void)a; /* UNUSED */
 
+       if (mine == NULL)
+               return (ARCHIVE_FATAL);
+
        if (mine->fd >= 0)
                close(mine->fd);
 
+       return (ARCHIVE_OK);
+}
+
+static int
+file_free(struct archive *a, void *client_data)
+{
+       struct write_file_data  *mine = (struct write_file_data *)client_data;
+
+       (void)a; /* UNUSED */
+
+       if (mine == NULL)
+               return (ARCHIVE_OK);
+
        archive_mstring_clean(&mine->filename);
        free(mine);
        return (ARCHIVE_OK);
index ea6ae0a..a8a0b81 100644 (file)
@@ -39,7 +39,7 @@ struct write_memory_data {
        unsigned char * buff;
 };
 
-static int     memory_write_close(struct archive *, void *);
+static int     memory_write_free(struct archive *, void *);
 static int     memory_write_open(struct archive *, void *);
 static ssize_t memory_write(struct archive *, void *, const void *buff, size_t);
 
@@ -61,8 +61,8 @@ archive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t
        mine->buff = buff;
        mine->size = buffSize;
        mine->client_size = used;
-       return (archive_write_open(a, mine,
-                   memory_write_open, memory_write, memory_write_close));
+       return (archive_write_open2(a, mine,
+                   memory_write_open, memory_write, NULL, memory_write_free));
 }
 
 static int
@@ -103,11 +103,13 @@ memory_write(struct archive *a, void *client_data, const void *buff, size_t leng
 }
 
 static int
-memory_write_close(struct archive *a, void *client_data)
+memory_write_free(struct archive *a, void *client_data)
 {
        struct write_memory_data *mine;
        (void)a; /* UNUSED */
        mine = client_data;
+       if (mine == NULL)
+               return (ARCHIVE_OK);
        free(mine);
        return (ARCHIVE_OK);
 }
index 27cba03..155fdd7 100644 (file)
@@ -89,6 +89,7 @@ struct archive_write {
        archive_open_callback   *client_opener;
        archive_write_callback  *client_writer;
        archive_close_callback  *client_closer;
+       archive_free_callback   *client_freer;
        void                    *client_data;
 
        /*
index 12de080..7dbe7b9 100644 (file)
@@ -82,7 +82,7 @@ void
 __archive_write_entry_filetype_unsupported(struct archive *a,
     struct archive_entry *entry, const char *format)
 {
-       char *name = NULL;
+       const char *name = NULL;
 
        switch (archive_entry_filetype(entry)) {
        /*
index 69af814..7f2e6ac 100644 (file)
@@ -1927,8 +1927,8 @@ compression_init_encoder_lzma(struct archive *a,
                return (ARCHIVE_FATAL);
        }
        lzmafilters = (lzma_filter *)(strm+1);
-       if (level > 6)
-               level = 6;
+       if (level > 9)
+               level = 9;
        if (lzma_lzma_preset(&lzma_opt, level)) {
                free(strm);
                lastrm->real_stream = NULL;
index 729f9c7..e066733 100644 (file)
@@ -250,7 +250,7 @@ archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
        const char *path;
        size_t len;
 
-       if (archive_entry_filetype(entry) == 0) {
+       if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {
                archive_set_error(&a->archive, -1, "Filetype required");
                return (ARCHIVE_FAILED);
        }
@@ -348,7 +348,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
        format_octal(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size);
        if (archive_entry_filetype(entry) == AE_IFBLK
            || archive_entry_filetype(entry) == AE_IFCHR)
-           format_octal(archive_entry_dev(entry), h + c_rdev_offset, c_rdev_size);
+           format_octal(archive_entry_rdev(entry), h + c_rdev_offset, c_rdev_size);
        else
            format_octal(0, h + c_rdev_offset, c_rdev_size);
        format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);
index 172fda6..f0f3980 100644 (file)
@@ -190,7 +190,7 @@ archive_write_newc_header(struct archive_write *a, struct archive_entry *entry)
        const char *path;
        size_t len;
 
-       if (archive_entry_filetype(entry) == 0) {
+       if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {
                archive_set_error(&a->archive, -1, "Filetype required");
                return (ARCHIVE_FAILED);
        }
index 5db414f..68e3fe3 100644 (file)
@@ -2178,7 +2178,8 @@ get_system_identitier(char *system_id, size_t size)
        strncpy(system_id, "Windows", size-1);
        system_id[size-1] = '\0';
 #else
-#error no way to get the system identifier on your platform.
+       strncpy(system_id, "Unknown", size-1);
+       system_id[size-1] = '\0';
 #endif
 }
 
index aa41e9a..619b771 100644 (file)
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_mtree.c 201171
 #include "archive.h"
 #include "archive_digest_private.h"
 #include "archive_entry.h"
+#include "archive_entry_private.h"
 #include "archive_private.h"
 #include "archive_rb.h"
 #include "archive_string.h"
@@ -82,24 +83,7 @@ struct dir_info {
 struct reg_info {
        int compute_sum;
        uint32_t crc;
-#ifdef ARCHIVE_HAS_MD5
-       unsigned char buf_md5[16];
-#endif
-#ifdef ARCHIVE_HAS_RMD160
-       unsigned char buf_rmd160[20];
-#endif
-#ifdef ARCHIVE_HAS_SHA1
-       unsigned char buf_sha1[20];
-#endif
-#ifdef ARCHIVE_HAS_SHA256
-       unsigned char buf_sha256[32];
-#endif
-#ifdef ARCHIVE_HAS_SHA384
-       unsigned char buf_sha384[48];
-#endif
-#ifdef ARCHIVE_HAS_SHA512
-       unsigned char buf_sha512[64];
-#endif
+       struct ae_digest digest;
 };
 
 struct mtree_entry {
@@ -1571,27 +1555,27 @@ sum_final(struct mtree_writer *mtree, struct reg_info *reg)
        }
 #ifdef ARCHIVE_HAS_MD5
        if (mtree->compute_sum & F_MD5)
-               archive_md5_final(&mtree->md5ctx, reg->buf_md5);
+               archive_md5_final(&mtree->md5ctx, reg->digest.md5);
 #endif
 #ifdef ARCHIVE_HAS_RMD160
        if (mtree->compute_sum & F_RMD160)
-               archive_rmd160_final(&mtree->rmd160ctx, reg->buf_rmd160);
+               archive_rmd160_final(&mtree->rmd160ctx, reg->digest.rmd160);
 #endif
 #ifdef ARCHIVE_HAS_SHA1
        if (mtree->compute_sum & F_SHA1)
-               archive_sha1_final(&mtree->sha1ctx, reg->buf_sha1);
+               archive_sha1_final(&mtree->sha1ctx, reg->digest.sha1);
 #endif
 #ifdef ARCHIVE_HAS_SHA256
        if (mtree->compute_sum & F_SHA256)
-               archive_sha256_final(&mtree->sha256ctx, reg->buf_sha256);
+               archive_sha256_final(&mtree->sha256ctx, reg->digest.sha256);
 #endif
 #ifdef ARCHIVE_HAS_SHA384
        if (mtree->compute_sum & F_SHA384)
-               archive_sha384_final(&mtree->sha384ctx, reg->buf_sha384);
+               archive_sha384_final(&mtree->sha384ctx, reg->digest.sha384);
 #endif
 #ifdef ARCHIVE_HAS_SHA512
        if (mtree->compute_sum & F_SHA512)
-               archive_sha512_final(&mtree->sha512ctx, reg->buf_sha512);
+               archive_sha512_final(&mtree->sha512ctx, reg->digest.sha512);
 #endif
        /* Save what types of sum are computed. */
        reg->compute_sum = mtree->compute_sum;
@@ -1621,42 +1605,47 @@ sum_write(struct archive_string *str, struct reg_info *reg)
                archive_string_sprintf(str, " cksum=%ju",
                    (uintmax_t)reg->crc);
        }
+
+#define append_digest(_s, _r, _t) \
+       strappend_bin(_s, _r->digest._t, sizeof(_r->digest._t))
+
 #ifdef ARCHIVE_HAS_MD5
        if (reg->compute_sum & F_MD5) {
                archive_strcat(str, " md5digest=");
-               strappend_bin(str, reg->buf_md5, sizeof(reg->buf_md5));
+               append_digest(str, reg, md5);
        }
 #endif
 #ifdef ARCHIVE_HAS_RMD160
        if (reg->compute_sum & F_RMD160) {
                archive_strcat(str, " rmd160digest=");
-               strappend_bin(str, reg->buf_rmd160, sizeof(reg->buf_rmd160));
+               append_digest(str, reg, rmd160);
        }
 #endif
 #ifdef ARCHIVE_HAS_SHA1
        if (reg->compute_sum & F_SHA1) {
                archive_strcat(str, " sha1digest=");
-               strappend_bin(str, reg->buf_sha1, sizeof(reg->buf_sha1));
+               append_digest(str, reg, sha1);
        }
 #endif
 #ifdef ARCHIVE_HAS_SHA256
        if (reg->compute_sum & F_SHA256) {
                archive_strcat(str, " sha256digest=");
-               strappend_bin(str, reg->buf_sha256, sizeof(reg->buf_sha256));
+               append_digest(str, reg, sha256);
        }
 #endif
 #ifdef ARCHIVE_HAS_SHA384
        if (reg->compute_sum & F_SHA384) {
                archive_strcat(str, " sha384digest=");
-               strappend_bin(str, reg->buf_sha384, sizeof(reg->buf_sha384));
+               append_digest(str, reg, sha384);
        }
 #endif
 #ifdef ARCHIVE_HAS_SHA512
        if (reg->compute_sum & F_SHA512) {
                archive_strcat(str, " sha512digest=");
-               strappend_bin(str, reg->buf_sha512, sizeof(reg->buf_sha512));
+               append_digest(str, reg, sha512);
        }
 #endif
+#undef append_digest
 }
 
 static int
index 3b0ffb3..1e35375 100644 (file)
@@ -681,7 +681,8 @@ xar_write_data(struct archive_write *a, const void *buff, size_t s)
 {
        struct xar *xar;
        enum la_zaction run;
-       size_t size, rsize;
+       size_t size = 0;
+       size_t rsize;
        int r;
 
        xar = (struct xar *)a->format_data;
@@ -2930,8 +2931,8 @@ compression_init_encoder_xz(struct archive *a,
                return (ARCHIVE_FATAL);
        }
        lzmafilters = (lzma_filter *)(strm+1);
-       if (level > 6)
-               level = 6;
+       if (level > 9)
+               level = 9;
        if (lzma_lzma_preset(&lzma_opt, level)) {
                free(strm);
                lastrm->real_stream = NULL;
index b0cd215..66a1f84 100644 (file)
@@ -584,6 +584,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
                        zip->entry_flags |= ZIP_ENTRY_FLAG_ENCRYPTED;
                        zip->entry_encryption = zip->encryption_type;
                        break;
+               case ENCRYPTION_NONE:
                default:
                        break;
                }
@@ -710,6 +711,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
                                    + AUTH_CODE_SIZE;
                                version_needed = 20;
                                break;
+                       case ENCRYPTION_NONE:
                        default:
                                break;
                        }
@@ -762,6 +764,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
                                if (version_needed < 20)
                                        version_needed = 20;
                                break;
+                       case ENCRYPTION_NONE:
                        default:
                                break;
                        }
@@ -1029,6 +1032,7 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
                                zip->cctx_valid = zip->hctx_valid = 1;
                        }
                        break;
+               case ENCRYPTION_NONE:
                default:
                        break;
                }
@@ -1117,6 +1121,7 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
                break;
 #endif
 
+       case COMPRESSION_UNSPECIFIED:
        default:
                archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
                    "Invalid ZIP compression type");
index cffe571..d4a52e3 100644 (file)
@@ -255,7 +255,8 @@ If supported, the default value is read from
 .Bl -tag -compact -width indent
 .It Cm compression-level
 The value is interpreted as a decimal integer specifying the
-compression level. Supported values are from 1 to 22.
+compression level. Supported values depend on the library version,
+common values are from 1 to 22.
 .El
 .It Format 7zip
 .Bl -tag -compact -width indent
index f16fd34..a484618 100644 (file)
@@ -24,6 +24,7 @@
  *
  * $FreeBSD$
  */
+#define __LIBARCHIVE_CONFIG_H_INCLUDED 1
 
 #include <osreldate.h>
 
 #define HAVE_STRFTIME 1
 #define HAVE_STRINGS_H 1
 #define HAVE_STRING_H 1
+#define HAVE_STRNLEN 1
 #define HAVE_STRRCHR 1
 #define HAVE_STRUCT_STATFS_F_NAMEMAX 1
 #define HAVE_STRUCT_STAT_ST_BIRTHTIME 1
index 1a2886f..a91f0c5 100644 (file)
@@ -244,7 +244,7 @@ Note that this format supports only 4 gigabyte files (unlike the
 older ASCII format, which supports 8 gigabyte files).
 .Pp
 In this format, hardlinked files are handled by setting the
-filesize to zero for each entry except the last one that
+filesize to zero for each entry except the first one that
 appears in the archive.
 .Ss New CRC Format
 The CRC format is identical to the new ASCII format described
index 908e7cd..2bf290c 100644 (file)
 #error This header is only to be used internally to libarchive.
 #endif
 
-pid_t
-__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout);
+int
+__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout,
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       HANDLE *out_child);
+#else
+       pid_t *out_child);
+#endif
 
 void
 __archive_check_child(int in, int out);
index 02dbd4b..ac255c4 100644 (file)
@@ -72,8 +72,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/filter_fork.c 182958 2008-09-12 05:33:00
 
 #include "filter_fork.h"
 
-pid_t
-__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
+int
+__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout,
+               pid_t *out_child)
 {
        pid_t child;
        int stdin_pipe[2], stdout_pipe[2], tmp;
@@ -177,7 +178,8 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
        fcntl(*child_stdout, F_SETFL, O_NONBLOCK);
        __archive_cmdline_free(cmdline);
 
-       return child;
+       *out_child = child;
+       return ARCHIVE_OK;
 
 #if HAVE_POSIX_SPAWNP
 actions_inited:
@@ -192,7 +194,7 @@ stdin_opened:
        close(stdin_pipe[1]);
 state_allocated:
        __archive_cmdline_free(cmdline);
-       return -1;
+       return ARCHIVE_FAILED;
 }
 
 void
index ad271fe..8d11179 100644 (file)
@@ -31,8 +31,9 @@
 
 #include "filter_fork.h"
 
-pid_t
-__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
+int
+__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout,
+               HANDLE *out_child)
 {
        HANDLE childStdout[2], childStdin[2],childStderr;
        SECURITY_ATTRIBUTES secAtts;
@@ -44,6 +45,7 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
        char *arg0, *ext;
        int i, l;
        DWORD fl, fl_old;
+       HANDLE child;
 
        childStdout[0] = childStdout[1] = INVALID_HANDLE_VALUE;
        childStdin[0] = childStdin[1] = INVALID_HANDLE_VALUE;
@@ -154,13 +156,20 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
        *child_stdout = _open_osfhandle((intptr_t)childStdout[0], _O_RDONLY);
        *child_stdin = _open_osfhandle((intptr_t)childStdin[1], _O_WRONLY);
        
+       child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
+               childInfo.dwProcessId);
+       if (child == NULL) // INVALID_HANDLE_VALUE ?
+               goto fail;
+
+       *out_child = child;
+
        CloseHandle(childStdout[1]);
        CloseHandle(childStdin[0]);
 
        archive_string_free(&cmdline);
        archive_string_free(&fullpath);
        __archive_cmdline_free(acmd);
-       return (childInfo.dwProcessId);
+       return ARCHIVE_OK;
 
 fail:
        if (childStdout[0] != INVALID_HANDLE_VALUE)
@@ -176,7 +185,7 @@ fail:
        archive_string_free(&cmdline);
        archive_string_free(&fullpath);
        __archive_cmdline_free(acmd);
-       return (-1);
+       return ARCHIVE_FAILED;
 }
 
 void
index f86357b..9b5d5dc 100644 (file)
@@ -45,7 +45,14 @@ typedef struct pollfd {
 #endif
 
 #include <mswsock.h>
+// Disable the typedef in mstcpip.h of MinGW.
+#define _TCP_INITIAL_RTO_PARAMETERS _TCP_INITIAL_RTO_PARAMETERS__AVOID
+#define TCP_INITIAL_RTO_PARAMETERS TCP_INITIAL_RTO_PARAMETERS__AVOID
+#define PTCP_INITIAL_RTO_PARAMETERS PTCP_INITIAL_RTO_PARAMETERS__AVOID
 #include <ws2tcpip.h>
+#undef _TCP_INITIAL_RTO_PARAMETERS
+#undef TCP_INITIAL_RTO_PARAMETERS
+#undef PTCP_INITIAL_RTO_PARAMETERS
 #include <windows.h>
 
 #include <process.h>
index e6d61ee..4245e02 100644 (file)
@@ -72,8 +72,6 @@ extern char** environ;
 # include <sys/sysctl.h>
 # include <sys/filio.h>
 # include <sys/wait.h>
-# include <sys/param.h>
-# include <sys/cpuset.h>
 # if defined(__FreeBSD__)
 #  define uv__accept4 accept4
 # endif
@@ -82,6 +80,11 @@ extern char** environ;
 # endif
 #endif
 
+#if defined(__FreeBSD__)
+# include <sys/param.h>
+# include <sys/cpuset.h>
+#endif
+
 #if defined(__MVS__)
 #include <sys/ioctl.h>
 #endif
index 04718db..aada889 100644 (file)
@@ -169,7 +169,10 @@ static WCHAR* search_path_join_test(const WCHAR* dir,
                                     size_t cwd_len) {
   WCHAR *result, *result_pos;
   DWORD attrs;
-  if (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') {
+  if (
+    (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') ||
+    (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'\\')) {
index 5c300fd..dcca766 100644 (file)
@@ -176,6 +176,12 @@ Going into `build` directory, you will find additional possibilities:
 You can build the zstd binary via buck by executing: `buck build programs:zstd` from the root of the repo.
 The output binary will be in `buck-out/gen/programs/`.
 
+## Testing
+
+You can run quick local smoke tests by executing the `playTest.sh` script from the `src/tests` directory.
+Two env variables `$ZSTD_BIN` and `$DATAGEN_BIN` are needed for the test script to locate the zstd and datagen binary.
+For information on CI testing, please refer to TESTING.md
+
 ## Status
 
 Zstandard is currently deployed within Facebook. It is used continuously to compress large amounts of data in multiple formats and use cases.
@@ -187,7 +193,7 @@ Zstandard is dual-licensed under [BSD](LICENSE) and [GPLv2](COPYING).
 
 ## Contributing
 
-The "dev" branch is the one where all contributions are merged before reaching "master".
-If you plan to propose a patch, please commit into the "dev" branch, or its own feature branch.
-Direct commit to "master" are not permitted.
+The `dev` branch is the one where all contributions are merged before reaching `release`.
+If you plan to propose a patch, please commit into the `dev` branch, or its own feature branch.
+Direct commit to `release` are not permitted.
 For more information, please read [CONTRIBUTING](CONTRIBUTING.md).
index 37b99c0..2e5a933 100644 (file)
@@ -1,7 +1,7 @@
 /* ******************************************************************
  * bitstream
  * Part of FSE library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  * You can contact the author at :
  * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -17,7 +17,6 @@
 #if defined (__cplusplus)
 extern "C" {
 #endif
-
 /*
 *  This API consists of small unitary functions, which must be inlined for best performance.
 *  Since link-time-optimization is not available for all compilers,
@@ -36,10 +35,12 @@ extern "C" {
 /*=========================================
 *  Target specific
 =========================================*/
-#if defined(__BMI__) && defined(__GNUC__)
-#  include <immintrin.h>   /* support for bextr (experimental) */
-#elif defined(__ICCARM__)
-#  include <intrinsics.h>
+#ifndef ZSTD_NO_INTRINSICS
+#  if defined(__BMI__) && defined(__GNUC__)
+#    include <immintrin.h>   /* support for bextr (experimental) */
+#  elif defined(__ICCARM__)
+#    include <intrinsics.h>
+#  endif
 #endif
 
 #define STREAM_ACCUMULATOR_MIN_32  25
@@ -141,8 +142,12 @@ MEM_STATIC unsigned BIT_highbit32 (U32 val)
     assert(val != 0);
     {
 #   if defined(_MSC_VER)   /* Visual */
-        unsigned long r=0;
-        return _BitScanReverse ( &r, val ) ? (unsigned)r : 0;
+#       if STATIC_BMI2 == 1
+               return _lzcnt_u32(val) ^ 31;
+#       else
+               unsigned long r = 0;
+               return _BitScanReverse(&r, val) ? (unsigned)r : 0;
+#       endif
 #   elif defined(__GNUC__) && (__GNUC__ >= 3)   /* Use GCC Intrinsic */
         return __builtin_clz (val) ^ 31;
 #   elif defined(__ICCARM__)    /* IAR Intrinsic */
@@ -198,7 +203,7 @@ MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
 MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
                             size_t value, unsigned nbBits)
 {
-    MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32);
+    DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32);
     assert(nbBits < BIT_MASK_SIZE);
     assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
     bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
@@ -271,7 +276,7 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
  */
 MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
 {
-    if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
+    if (srcSize < 1) { ZSTD_memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
 
     bitD->start = (const char*)srcBuffer;
     bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer);
@@ -317,12 +322,12 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si
     return srcSize;
 }
 
-MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
+MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
 {
     return bitContainer >> start;
 }
 
-MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
+MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
 {
     U32 const regMask = sizeof(bitContainer)*8 - 1;
     /* if start > regMask, bitstream is corrupted, and result is undefined */
@@ -330,10 +335,14 @@ MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 co
     return (bitContainer >> (start & regMask)) & BIT_mask[nbBits];
 }
 
-MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
+MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
 {
+#if defined(STATIC_BMI2) && STATIC_BMI2 == 1
+       return  _bzhi_u64(bitContainer, nbBits);
+#else
     assert(nbBits < BIT_MASK_SIZE);
     return bitContainer & BIT_mask[nbBits];
+#endif
 }
 
 /*! BIT_lookBits() :
@@ -342,7 +351,7 @@ MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
  *  On 32-bits, maxNbBits==24.
  *  On 64-bits, maxNbBits==56.
  * @return : value extracted */
-MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
+MEM_STATIC  FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t*  bitD, U32 nbBits)
 {
     /* arbitrate between double-shift and shift+mask */
 #if 1
@@ -365,7 +374,7 @@ MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
     return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
 }
 
-MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
+MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
 {
     bitD->bitsConsumed += nbBits;
 }
@@ -374,7 +383,7 @@ MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
  *  Read (consume) next n bits from local register and update.
  *  Pay attention to not read more than nbBits contained into local register.
  * @return : extracted value. */
-MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
+MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
 {
     size_t const value = BIT_lookBits(bitD, nbBits);
     BIT_skipBits(bitD, nbBits);
index 95e9483..f717855 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
 #endif
 
 /**
+  On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC).
+  This explictly marks such functions as __cdecl so that the code will still compile
+  if a CC other than __cdecl has been made the default.
+*/
+#if  defined(_MSC_VER)
+#  define WIN_CDECL __cdecl
+#else
+#  define WIN_CDECL
+#endif
+
+/**
  * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant
  * parameters. They must be inlined for the compiler to eliminate the constant
  * branches.
@@ -79,6 +90,7 @@
 #  endif
 #endif
 
+
 /* target attribute */
 #ifndef __has_attribute
   #define __has_attribute(x) 0  /* Compatibility with non-clang compilers. */
 #    include <mmintrin.h>   /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
 #    define PREFETCH_L1(ptr)  _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
 #    define PREFETCH_L2(ptr)  _mm_prefetch((const char*)(ptr), _MM_HINT_T1)
-#    elif defined(__aarch64__)
-#     define PREFETCH_L1(ptr)  __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr)))
-#     define PREFETCH_L2(ptr)  __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr)))
 #  elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )
 #    define PREFETCH_L1(ptr)  __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
 #    define PREFETCH_L2(ptr)  __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
+#  elif defined(__aarch64__)
+#    define PREFETCH_L1(ptr)  __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr)))
+#    define PREFETCH_L2(ptr)  __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr)))
 #  else
 #    define PREFETCH_L1(ptr) (void)(ptr)  /* disabled */
 #    define PREFETCH_L2(ptr) (void)(ptr)  /* disabled */
 
 /* vectorization
  * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax */
-#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__)
+#if !defined(__INTEL_COMPILER) && !defined(__clang__) && !defined(__LCC__) && defined(__GNUC__)
 #  if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5)
 #    define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize")))
 #  else
 #  pragma warning(disable : 4324)        /* disable: C4324: padded structure */
 #endif
 
+/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/
+#ifndef STATIC_BMI2
+#  if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86))
+#    ifdef __AVX2__  //MSVC does not have a BMI2 specific flag, but every CPU that supports AVX2 also supports BMI2
+#       define STATIC_BMI2 1
+#    endif
+#  endif
+#endif
+
+#ifndef STATIC_BMI2
+    #define STATIC_BMI2 0
+#endif
+
+/* compat. with non-clang compilers */
+#ifndef __has_builtin
+#  define __has_builtin(x) 0
+#endif
+
+/* compat. with non-clang compilers */
+#ifndef __has_feature
+#  define __has_feature(x) 0
+#endif
+
+/* detects whether we are being compiled under msan */
+#ifndef ZSTD_MEMORY_SANITIZER
+#  if __has_feature(memory_sanitizer)
+#    define ZSTD_MEMORY_SANITIZER 1
+#  else
+#    define ZSTD_MEMORY_SANITIZER 0
+#  endif
+#endif
+
+#if ZSTD_MEMORY_SANITIZER
+/* Not all platforms that support msan provide sanitizers/msan_interface.h.
+ * We therefore declare the functions we need ourselves, rather than trying to
+ * include the header file... */
+#include <stddef.h>  /* size_t */
+#define ZSTD_DEPS_NEED_STDINT
+#include "zstd_deps.h"  /* intptr_t */
+
+/* Make memory region fully initialized (without changing its contents). */
+void __msan_unpoison(const volatile void *a, size_t size);
+
+/* Make memory region fully uninitialized (without changing its contents).
+   This is a legacy interface that does not update origin information. Use
+   __msan_allocated_memory() instead. */
+void __msan_poison(const volatile void *a, size_t size);
+
+/* Returns the offset of the first (at least partially) poisoned byte in the
+   memory range, or -1 if the whole range is good. */
+intptr_t __msan_test_shadow(const volatile void *x, size_t size);
+#endif
+
+/* detects whether we are being compiled under asan */
+#ifndef ZSTD_ADDRESS_SANITIZER
+#  if __has_feature(address_sanitizer)
+#    define ZSTD_ADDRESS_SANITIZER 1
+#  elif defined(__SANITIZE_ADDRESS__)
+#    define ZSTD_ADDRESS_SANITIZER 1
+#  else
+#    define ZSTD_ADDRESS_SANITIZER 0
+#  endif
+#endif
+
+#if ZSTD_ADDRESS_SANITIZER
+/* Not all platforms that support asan provide sanitizers/asan_interface.h.
+ * We therefore declare the functions we need ourselves, rather than trying to
+ * include the header file... */
+#include <stddef.h>  /* size_t */
+
+/**
+ * Marks a memory region (<c>[addr, addr+size)</c>) as unaddressable.
+ *
+ * This memory must be previously allocated by your program. Instrumented
+ * code is forbidden from accessing addresses in this region until it is
+ * unpoisoned. This function is not guaranteed to poison the entire region -
+ * it could poison only a subregion of <c>[addr, addr+size)</c> due to ASan
+ * alignment restrictions.
+ *
+ * \note This function is not thread-safe because no two threads can poison or
+ * unpoison memory in the same memory region simultaneously.
+ *
+ * \param addr Start of memory region.
+ * \param size Size of memory region. */
+void __asan_poison_memory_region(void const volatile *addr, size_t size);
+
+/**
+ * Marks a memory region (<c>[addr, addr+size)</c>) as addressable.
+ *
+ * This memory must be previously allocated by your program. Accessing
+ * addresses in this region is allowed until this region is poisoned again.
+ * This function could unpoison a super-region of <c>[addr, addr+size)</c> due
+ * to ASan alignment restrictions.
+ *
+ * \note This function is not thread-safe because no two threads can
+ * poison or unpoison memory in the same memory region simultaneously.
+ *
+ * \param addr Start of memory region.
+ * \param size Size of memory region. */
+void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
+#endif
+
 #endif /* ZSTD_COMPILER_H */
index 6e8a974..8acd33b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -16,8 +16,6 @@
  * https://github.com/facebook/folly/blob/master/folly/CpuId.h
  */
 
-#include <string.h>
-
 #include "mem.h"
 
 #ifdef _MSC_VER
index f303f4a..bb863c9 100644 (file)
@@ -1,7 +1,7 @@
 /* ******************************************************************
  * debug
  * Part of FSE library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  * You can contact the author at :
  * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
index ac62248..3b2a320 100644 (file)
@@ -1,7 +1,7 @@
 /* ******************************************************************
  * debug
  * Part of FSE library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  * You can contact the author at :
  * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -51,15 +51,6 @@ extern "C" {
 #endif
 
 
-/* DEBUGFILE can be defined externally,
- * typically through compiler command line.
- * note : currently useless.
- * Value must be stderr or stdout */
-#ifndef DEBUGFILE
-#  define DEBUGFILE stderr
-#endif
-
-
 /* recommended values for DEBUGLEVEL :
  * 0 : release mode, no debug, all run-time checks disabled
  * 1 : enables assert() only, no display
@@ -76,7 +67,8 @@ extern "C" {
  */
 
 #if (DEBUGLEVEL>=1)
-#  include <assert.h>
+#  define ZSTD_DEPS_NEED_ASSERT
+#  include "zstd_deps.h"
 #else
 #  ifndef assert   /* assert may be already defined, due to prior #include <assert.h> */
 #    define assert(condition) ((void)0)   /* disable assert (default) */
@@ -84,7 +76,8 @@ extern "C" {
 #endif
 
 #if (DEBUGLEVEL>=2)
-#  include <stdio.h>
+#  define ZSTD_DEPS_NEED_IO
+#  include "zstd_deps.h"
 extern int g_debuglevel; /* the variable is only declared,
                             it actually lives in debug.c,
                             and is shared by the whole process.
@@ -92,14 +85,14 @@ extern int g_debuglevel; /* the variable is only declared,
                             It's useful when enabling very verbose levels
                             on selective conditions (such as position in src) */
 
-#  define RAWLOG(l, ...) {                                      \
-                if (l<=g_debuglevel) {                          \
-                    fprintf(stderr, __VA_ARGS__);               \
+#  define RAWLOG(l, ...) {                                       \
+                if (l<=g_debuglevel) {                           \
+                    ZSTD_DEBUG_PRINT(__VA_ARGS__);               \
             }   }
-#  define DEBUGLOG(l, ...) {                                    \
-                if (l<=g_debuglevel) {                          \
-                    fprintf(stderr, __FILE__ ": " __VA_ARGS__); \
-                    fprintf(stderr, " \n");                     \
+#  define DEBUGLOG(l, ...) {                                     \
+                if (l<=g_debuglevel) {                           \
+                    ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \
+                    ZSTD_DEBUG_PRINT(" \n");                     \
             }   }
 #else
 #  define RAWLOG(l, ...)      {}    /* disabled */
index 9d3e4e8..41cd695 100644 (file)
@@ -1,6 +1,6 @@
 /* ******************************************************************
  * Common functions of New Generation Entropy library
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  *  You can contact the author at :
  *  - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -38,8 +38,31 @@ const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); }
 /*-**************************************************************
 *  FSE NCount encoding-decoding
 ****************************************************************/
-size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
-                 const void* headerBuffer, size_t hbSize)
+static U32 FSE_ctz(U32 val)
+{
+    assert(val != 0);
+    {
+#   if defined(_MSC_VER)   /* Visual */
+        unsigned long r=0;
+        return _BitScanForward(&r, val) ? (unsigned)r : 0;
+#   elif defined(__GNUC__) && (__GNUC__ >= 3)   /* GCC Intrinsic */
+        return __builtin_ctz(val);
+#   elif defined(__ICCARM__)    /* IAR Intrinsic */
+        return __CTZ(val);
+#   else   /* Software version */
+        U32 count = 0;
+        while ((val & 1) == 0) {
+            val >>= 1;
+            ++count;
+        }
+        return count;
+#   endif
+    }
+}
+
+FORCE_INLINE_TEMPLATE
+size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
+                           const void* headerBuffer, size_t hbSize)
 {
     const BYTE* const istart = (const BYTE*) headerBuffer;
     const BYTE* const iend = istart + hbSize;
@@ -50,23 +73,23 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t
     U32 bitStream;
     int bitCount;
     unsigned charnum = 0;
+    unsigned const maxSV1 = *maxSVPtr + 1;
     int previous0 = 0;
 
-    if (hbSize < 4) {
-        /* This function only works when hbSize >= 4 */
-        char buffer[4];
-        memset(buffer, 0, sizeof(buffer));
-        memcpy(buffer, headerBuffer, hbSize);
+    if (hbSize < 8) {
+        /* This function only works when hbSize >= 8 */
+        char buffer[8] = {0};
+        ZSTD_memcpy(buffer, headerBuffer, hbSize);
         {   size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr,
                                                     buffer, sizeof(buffer));
             if (FSE_isError(countSize)) return countSize;
             if (countSize > hbSize) return ERROR(corruption_detected);
             return countSize;
     }   }
-    assert(hbSize >= 4);
+    assert(hbSize >= 8);
 
     /* init */
-    memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0]));   /* all symbols not present in NCount have a frequency of 0 */
+    ZSTD_memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0]));   /* all symbols not present in NCount have a frequency of 0 */
     bitStream = MEM_readLE32(ip);
     nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG;   /* extract tableLog */
     if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
@@ -77,36 +100,58 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t
     threshold = 1<<nbBits;
     nbBits++;
 
-    while ((remaining>1) & (charnum<=*maxSVPtr)) {
+    for (;;) {
         if (previous0) {
-            unsigned n0 = charnum;
-            while ((bitStream & 0xFFFF) == 0xFFFF) {
-                n0 += 24;
-                if (ip < iend-5) {
-                    ip += 2;
-                    bitStream = MEM_readLE32(ip) >> bitCount;
+            /* Count the number of repeats. Each time the
+             * 2-bit repeat code is 0b11 there is another
+             * repeat.
+             * Avoid UB by setting the high bit to 1.
+             */
+            int repeats = FSE_ctz(~bitStream | 0x80000000) >> 1;
+            while (repeats >= 12) {
+                charnum += 3 * 12;
+                if (LIKELY(ip <= iend-7)) {
+                    ip += 3;
                 } else {
-                    bitStream >>= 16;
-                    bitCount   += 16;
-            }   }
-            while ((bitStream & 3) == 3) {
-                n0 += 3;
-                bitStream >>= 2;
-                bitCount += 2;
+                    bitCount -= (int)(8 * (iend - 7 - ip));
+                    bitCount &= 31;
+                    ip = iend - 4;
+                }
+                bitStream = MEM_readLE32(ip) >> bitCount;
+                repeats = FSE_ctz(~bitStream | 0x80000000) >> 1;
             }
-            n0 += bitStream & 3;
+            charnum += 3 * repeats;
+            bitStream >>= 2 * repeats;
+            bitCount += 2 * repeats;
+
+            /* Add the final repeat which isn't 0b11. */
+            assert((bitStream & 3) < 3);
+            charnum += bitStream & 3;
             bitCount += 2;
-            if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall);
-            while (charnum < n0) normalizedCounter[charnum++] = 0;
-            if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
+
+            /* This is an error, but break and return an error
+             * at the end, because returning out of a loop makes
+             * it harder for the compiler to optimize.
+             */
+            if (charnum >= maxSV1) break;
+
+            /* We don't need to set the normalized count to 0
+             * because we already memset the whole buffer to 0.
+             */
+
+            if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
                 assert((bitCount >> 3) <= 3); /* For first condition to work */
                 ip += bitCount>>3;
                 bitCount &= 7;
-                bitStream = MEM_readLE32(ip) >> bitCount;
             } else {
-                bitStream >>= 2;
-        }   }
-        {   int const max = (2*threshold-1) - remaining;
+                bitCount -= (int)(8 * (iend - 4 - ip));
+                bitCount &= 31;
+                ip = iend - 4;
+            }
+            bitStream = MEM_readLE32(ip) >> bitCount;
+        }
+        {
+            int const max = (2*threshold-1) - remaining;
             int count;
 
             if ((bitStream & (threshold-1)) < (U32)max) {
@@ -119,24 +164,43 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t
             }
 
             count--;   /* extra accuracy */
-            remaining -= count < 0 ? -count : count;   /* -1 means +1 */
+            /* When it matters (small blocks), this is a
+             * predictable branch, because we don't use -1.
+             */
+            if (count >= 0) {
+                remaining -= count;
+            } else {
+                assert(count == -1);
+                remaining += count;
+            }
             normalizedCounter[charnum++] = (short)count;
             previous0 = !count;
-            while (remaining < threshold) {
-                nbBits--;
-                threshold >>= 1;
+
+            assert(threshold > 1);
+            if (remaining < threshold) {
+                /* This branch can be folded into the
+                 * threshold update condition because we
+                 * know that threshold > 1.
+                 */
+                if (remaining <= 1) break;
+                nbBits = BIT_highbit32(remaining) + 1;
+                threshold = 1 << (nbBits - 1);
             }
+            if (charnum >= maxSV1) break;
 
-            if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
+            if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
                 ip += bitCount>>3;
                 bitCount &= 7;
             } else {
                 bitCount -= (int)(8 * (iend - 4 - ip));
+                bitCount &= 31;
                 ip = iend - 4;
             }
-            bitStream = MEM_readLE32(ip) >> (bitCount & 31);
-    }   }   /* while ((remaining>1) & (charnum<=*maxSVPtr)) */
+            bitStream = MEM_readLE32(ip) >> bitCount;
+    }   }
     if (remaining != 1) return ERROR(corruption_detected);
+    /* Only possible when there are too many zeros. */
+    if (charnum > maxSV1) return ERROR(maxSymbolValue_tooSmall);
     if (bitCount > 32) return ERROR(corruption_detected);
     *maxSVPtr = charnum-1;
 
@@ -144,6 +208,43 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t
     return ip-istart;
 }
 
+/* Avoids the FORCE_INLINE of the _body() function. */
+static size_t FSE_readNCount_body_default(
+        short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
+        const void* headerBuffer, size_t hbSize)
+{
+    return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
+}
+
+#if DYNAMIC_BMI2
+TARGET_ATTRIBUTE("bmi2") static size_t FSE_readNCount_body_bmi2(
+        short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
+        const void* headerBuffer, size_t hbSize)
+{
+    return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
+}
+#endif
+
+size_t FSE_readNCount_bmi2(
+        short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
+        const void* headerBuffer, size_t hbSize, int bmi2)
+{
+#if DYNAMIC_BMI2
+    if (bmi2) {
+        return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
+    }
+#endif
+    (void)bmi2;
+    return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
+}
+
+size_t FSE_readNCount(
+        short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
+        const void* headerBuffer, size_t hbSize)
+{
+    return FSE_readNCount_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize, /* bmi2 */ 0);
+}
+
 
 /*! HUF_readStats() :
     Read compact Huffman tree, saved by HUF_writeCTable().
@@ -156,6 +257,17 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
                      U32* nbSymbolsPtr, U32* tableLogPtr,
                      const void* src, size_t srcSize)
 {
+    U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32];
+    return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* bmi2 */ 0);
+}
+
+FORCE_INLINE_TEMPLATE size_t
+HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats,
+                   U32* nbSymbolsPtr, U32* tableLogPtr,
+                   const void* src, size_t srcSize,
+                   void* workSpace, size_t wkspSize,
+                   int bmi2)
+{
     U32 weightTotal;
     const BYTE* ip = (const BYTE*) src;
     size_t iSize;
@@ -163,7 +275,7 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
 
     if (!srcSize) return ERROR(srcSize_wrong);
     iSize = ip[0];
-    /* memset(huffWeight, 0, hwSize);   *//* is not necessary, even though some analyzer complain ... */
+    /* ZSTD_memset(huffWeight, 0, hwSize);   *//* is not necessary, even though some analyzer complain ... */
 
     if (iSize >= 128) {  /* special header */
         oSize = iSize - 127;
@@ -177,14 +289,14 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
                 huffWeight[n+1] = ip[n/2] & 15;
     }   }   }
     else  {   /* header compressed with FSE (normal case) */
-        FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)];  /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */
         if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
-        oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6);   /* max (hwSize-1) values decoded, as last one is implied */
+        /* max (hwSize-1) values decoded, as last one is implied */
+        oSize = FSE_decompress_wksp_bmi2(huffWeight, hwSize-1, ip+1, iSize, 6, workSpace, wkspSize, bmi2);
         if (FSE_isError(oSize)) return oSize;
     }
 
     /* collect weight stats */
-    memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
+    ZSTD_memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
     weightTotal = 0;
     {   U32 n; for (n=0; n<oSize; n++) {
             if (huffWeight[n] >= HUF_TABLELOG_MAX) return ERROR(corruption_detected);
@@ -214,3 +326,37 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
     *nbSymbolsPtr = (U32)(oSize+1);
     return iSize+1;
 }
+
+/* Avoids the FORCE_INLINE of the _body() function. */
+static size_t HUF_readStats_body_default(BYTE* huffWeight, size_t hwSize, U32* rankStats,
+                     U32* nbSymbolsPtr, U32* tableLogPtr,
+                     const void* src, size_t srcSize,
+                     void* workSpace, size_t wkspSize)
+{
+    return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 0);
+}
+
+#if DYNAMIC_BMI2
+static TARGET_ATTRIBUTE("bmi2") size_t HUF_readStats_body_bmi2(BYTE* huffWeight, size_t hwSize, U32* rankStats,
+                     U32* nbSymbolsPtr, U32* tableLogPtr,
+                     const void* src, size_t srcSize,
+                     void* workSpace, size_t wkspSize)
+{
+    return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1);
+}
+#endif
+
+size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats,
+                     U32* nbSymbolsPtr, U32* tableLogPtr,
+                     const void* src, size_t srcSize,
+                     void* workSpace, size_t wkspSize,
+                     int bmi2)
+{
+#if DYNAMIC_BMI2
+    if (bmi2) {
+        return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
+    }
+#endif
+    (void)bmi2;
+    return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
+}
index cd43752..6d1135f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -48,6 +48,7 @@ const char* ERR_getErrorString(ERR_enum code)
     case PREFIX(frameIndex_tooLarge): return "Frame index is too large";
     case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking";
     case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong";
+    case PREFIX(srcBuffer_wrong): return "Source buffer is wrong";
     case PREFIX(maxCode):
     default: return notErrorCode;
     }
index 982cf8e..6d8b9f7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -21,8 +21,8 @@ extern "C" {
 /* ****************************************
 *  Dependencies
 ******************************************/
-#include <stddef.h>        /* size_t */
-#include "zstd_errors.h"  /* enum list */
+#include "../zstd_errors.h"  /* enum list */
+#include "zstd_deps.h"       /* size_t */
 
 
 /* ****************************************
index ff54e70..19dd4fe 100644 (file)
@@ -1,7 +1,7 @@
 /* ******************************************************************
  * FSE : Finite State Entropy codec
  * Public Prototypes declaration
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  * You can contact the author at :
  * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -23,7 +23,7 @@ extern "C" {
 /*-*****************************************
 *  Dependencies
 ******************************************/
-#include <stddef.h>    /* size_t, ptrdiff_t */
+#include "zstd_deps.h"    /* size_t, ptrdiff_t */
 
 
 /*-*****************************************
@@ -137,10 +137,16 @@ FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize
 /*! FSE_normalizeCount():
     normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
     'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
+    useLowProbCount is a boolean parameter which trades off compressed size for
+    faster header decoding. When it is set to 1, the compressed data will be slightly
+    smaller. And when it is set to 0, FSE_readNCount() and FSE_buildDTable() will be
+    faster. If you are compressing a small amount of data (< 2 KB) then useLowProbCount=0
+    is a good default, since header deserialization makes a big speed difference.
+    Otherwise, useLowProbCount=1 is a good default, since the speed difference is small.
     @return : tableLog,
               or an errorCode, which can be tested using FSE_isError() */
 FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog,
-                    const unsigned* count, size_t srcSize, unsigned maxSymbolValue);
+                    const unsigned* count, size_t srcSize, unsigned maxSymbolValue, unsigned useLowProbCount);
 
 /*! FSE_NCountWriteBound():
     Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
@@ -228,6 +234,13 @@ FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter,
                            unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
                            const void* rBuffer, size_t rBuffSize);
 
+/*! FSE_readNCount_bmi2():
+ * Same as FSE_readNCount() but pass bmi2=1 when your CPU supports BMI2 and 0 otherwise.
+ */
+FSE_PUBLIC_API size_t FSE_readNCount_bmi2(short* normalizedCounter,
+                           unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
+                           const void* rBuffer, size_t rBuffSize, int bmi2);
+
 /*! Constructor and Destructor of FSE_DTable.
     Note that its size depends on 'tableLog' */
 typedef unsigned FSE_DTable;   /* don't allocate that. It's just a way to be more restrictive than void* */
@@ -288,12 +301,12 @@ If there is an error, the function will return an error code, which can be teste
 *******************************************/
 /* FSE buffer bounds */
 #define FSE_NCOUNTBOUND 512
-#define FSE_BLOCKBOUND(size) (size + (size>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */)
+#define FSE_BLOCKBOUND(size) ((size) + ((size)>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */)
 #define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size))   /* Macro version, useful for static allocation */
 
 /* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
-#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue)   (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2))
-#define FSE_DTABLE_SIZE_U32(maxTableLog)                   (1 + (1<<maxTableLog))
+#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue)   (1 + (1<<((maxTableLog)-1)) + (((maxSymbolValue)+1)*2))
+#define FSE_DTABLE_SIZE_U32(maxTableLog)                   (1 + (1<<(maxTableLog)))
 
 /* or use the size to malloc() space directly. Pay attention to alignment restrictions though */
 #define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue)   (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable))
@@ -309,9 +322,9 @@ unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsi
 
 /* FSE_compress_wksp() :
  * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
- * FSE_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
+ * FSE_COMPRESS_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
  */
-#define FSE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue)   ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) )
+#define FSE_COMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue)   ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) )
 size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
 
 size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits);
@@ -322,18 +335,30 @@ size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue);
 
 /* FSE_buildCTable_wksp() :
  * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
- * `wkspSize` must be >= `(1<<tableLog)`.
+ * `wkspSize` must be >= `FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)` of `unsigned`.
  */
+#define FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog) (maxSymbolValue + 2 + (1ull << (tableLog - 2)))
+#define FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) (sizeof(unsigned) * FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog))
 size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
 
+#define FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) (sizeof(short) * (maxSymbolValue + 1) + (1ULL << maxTableLog) + 8)
+#define FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ((FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) + sizeof(unsigned) - 1) / sizeof(unsigned))
+FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
+/**< Same as FSE_buildDTable(), using an externally allocated `workspace` produced with `FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxSymbolValue)` */
+
 size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
 /**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
 
 size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue);
 /**< build a fake FSE_DTable, designed to always generate the same symbolValue */
 
-size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog);
-/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DTABLE_SIZE_U32(maxLog)` */
+#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1)
+#define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned))
+size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize);
+/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)` */
+
+size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2);
+/**< Same as FSE_decompress_wksp() but with dynamic BMI2 support. Pass 1 if your CPU supports BMI2 or 0 if it doesn't. */
 
 typedef enum {
    FSE_repeat_none,  /**< Cannot use the previous table */
@@ -644,6 +669,9 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
 #ifndef FSE_DEFAULT_MEMORY_USAGE
 #  define FSE_DEFAULT_MEMORY_USAGE 13
 #endif
+#if (FSE_DEFAULT_MEMORY_USAGE > FSE_MAX_MEMORY_USAGE)
+#  error "FSE_DEFAULT_MEMORY_USAGE must be <= FSE_MAX_MEMORY_USAGE"
+#endif
 
 /*!FSE_MAX_SYMBOL_VALUE :
 *  Maximum symbol value authorized.
@@ -677,7 +705,7 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
 #  error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
 #endif
 
-#define FSE_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3)
+#define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3)
 
 
 #endif /* FSE_STATIC_LINKING_ONLY */
index bcc2223..f4ff58f 100644 (file)
@@ -1,6 +1,6 @@
 /* ******************************************************************
  * FSE : Finite State Entropy decoder
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  *  You can contact the author at :
  *  - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
 /* **************************************************************
 *  Includes
 ****************************************************************/
-#include <stdlib.h>     /* malloc, free, qsort */
-#include <string.h>     /* memcpy, memset */
+#include "debug.h"      /* assert */
 #include "bitstream.h"
 #include "compiler.h"
 #define FSE_STATIC_LINKING_ONLY
 #include "fse.h"
 #include "error_private.h"
+#define ZSTD_DEPS_NEED_MALLOC
+#include "zstd_deps.h"
 
 
 /* **************************************************************
 FSE_DTable* FSE_createDTable (unsigned tableLog)
 {
     if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
-    return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );
+    return (FSE_DTable*)ZSTD_malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );
 }
 
 void FSE_freeDTable (FSE_DTable* dt)
 {
-    free(dt);
+    ZSTD_free(dt);
 }
 
-size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
+static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
 {
     void* const tdPtr = dt+1;   /* because *dt is unsigned, 32-bits aligned on 32-bits */
     FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr);
-    U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1];
+    U16* symbolNext = (U16*)workSpace;
+    BYTE* spread = (BYTE*)(symbolNext + maxSymbolValue + 1);
 
     U32 const maxSV1 = maxSymbolValue + 1;
     U32 const tableSize = 1 << tableLog;
     U32 highThreshold = tableSize-1;
 
     /* Sanity Checks */
+    if (FSE_BUILD_DTABLE_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(maxSymbolValue_tooLarge);
     if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
     if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
 
@@ -95,11 +98,57 @@ size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned
                     if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
                     symbolNext[s] = normalizedCounter[s];
         }   }   }
-        memcpy(dt, &DTableH, sizeof(DTableH));
+        ZSTD_memcpy(dt, &DTableH, sizeof(DTableH));
     }
 
     /* Spread symbols */
-    {   U32 const tableMask = tableSize-1;
+    if (highThreshold == tableSize - 1) {
+        size_t const tableMask = tableSize-1;
+        size_t const step = FSE_TABLESTEP(tableSize);
+        /* First lay down the symbols in order.
+         * We use a uint64_t to lay down 8 bytes at a time. This reduces branch
+         * misses since small blocks generally have small table logs, so nearly
+         * all symbols have counts <= 8. We ensure we have 8 bytes at the end of
+         * our buffer to handle the over-write.
+         */
+        {
+            U64 const add = 0x0101010101010101ull;
+            size_t pos = 0;
+            U64 sv = 0;
+            U32 s;
+            for (s=0; s<maxSV1; ++s, sv += add) {
+                int i;
+                int const n = normalizedCounter[s];
+                MEM_write64(spread + pos, sv);
+                for (i = 8; i < n; i += 8) {
+                    MEM_write64(spread + pos + i, sv);
+                }
+                pos += n;
+            }
+        }
+        /* Now we spread those positions across the table.
+         * The benefit of doing it in two stages is that we avoid the the
+         * variable size inner loop, which caused lots of branch misses.
+         * Now we can run through all the positions without any branch misses.
+         * We unroll the loop twice, since that is what emperically worked best.
+         */
+        {
+            size_t position = 0;
+            size_t s;
+            size_t const unroll = 2;
+            assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */
+            for (s = 0; s < (size_t)tableSize; s += unroll) {
+                size_t u;
+                for (u = 0; u < unroll; ++u) {
+                    size_t const uPosition = (position + (u * step)) & tableMask;
+                    tableDecode[uPosition].symbol = spread[s + u];
+                }
+                position = (position + (unroll * step)) & tableMask;
+            }
+            assert(position == 0);
+        }
+    } else {
+        U32 const tableMask = tableSize-1;
         U32 const step = FSE_TABLESTEP(tableSize);
         U32 s, position = 0;
         for (s=0; s<maxSV1; s++) {
@@ -124,6 +173,11 @@ size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned
     return 0;
 }
 
+size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
+{
+    return FSE_buildDTable_internal(dt, normalizedCounter, maxSymbolValue, tableLog, workSpace, wkspSize);
+}
+
 
 #ifndef FSE_COMMONDEFS_ONLY
 
@@ -251,36 +305,99 @@ size_t FSE_decompress_usingDTable(void* dst, size_t originalSize,
 }
 
 
-size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog)
+size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize)
+{
+    return FSE_decompress_wksp_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, /* bmi2 */ 0);
+}
+
+typedef struct {
+    short ncount[FSE_MAX_SYMBOL_VALUE + 1];
+    FSE_DTable dtable[1]; /* Dynamically sized */
+} FSE_DecompressWksp;
+
+
+FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body(
+        void* dst, size_t dstCapacity,
+        const void* cSrc, size_t cSrcSize,
+        unsigned maxLog, void* workSpace, size_t wkspSize,
+        int bmi2)
 {
     const BYTE* const istart = (const BYTE*)cSrc;
     const BYTE* ip = istart;
-    short counting[FSE_MAX_SYMBOL_VALUE+1];
     unsigned tableLog;
     unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
+    FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace;
+
+    DEBUG_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0);
+    if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC);
 
     /* normal FSE decoding mode */
-    size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
-    if (FSE_isError(NCountLength)) return NCountLength;
-    /* if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); */  /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */
-    if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
-    ip += NCountLength;
-    cSrcSize -= NCountLength;
+    {
+        size_t const NCountLength = FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2);
+        if (FSE_isError(NCountLength)) return NCountLength;
+        if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
+        assert(NCountLength <= cSrcSize);
+        ip += NCountLength;
+        cSrcSize -= NCountLength;
+    }
+
+    if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge);
+    workSpace = wksp->dtable + FSE_DTABLE_SIZE_U32(tableLog);
+    wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog);
+
+    CHECK_F( FSE_buildDTable_internal(wksp->dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) );
+
+    {
+        const void* ptr = wksp->dtable;
+        const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
+        const U32 fastMode = DTableH->fastMode;
 
-    CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) );
+        /* select fast mode (static) */
+        if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 1);
+        return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 0);
+    }
+}
+
+/* Avoids the FORCE_INLINE of the _body() function. */
+static size_t FSE_decompress_wksp_body_default(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize)
+{
+    return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 0);
+}
+
+#if DYNAMIC_BMI2
+TARGET_ATTRIBUTE("bmi2") static size_t FSE_decompress_wksp_body_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize)
+{
+    return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 1);
+}
+#endif
 
-    return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace);   /* always return, even if it is an error code */
+size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2)
+{
+#if DYNAMIC_BMI2
+    if (bmi2) {
+        return FSE_decompress_wksp_body_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize);
+    }
+#endif
+    (void)bmi2;
+    return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize);
 }
 
 
 typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];
 
+#ifndef ZSTD_NO_UNUSED_FUNCTIONS
+size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) {
+    U32 wksp[FSE_BUILD_DTABLE_WKSP_SIZE_U32(FSE_TABLELOG_ABSOLUTE_MAX, FSE_MAX_SYMBOL_VALUE)];
+    return FSE_buildDTable_wksp(dt, normalizedCounter, maxSymbolValue, tableLog, wksp, sizeof(wksp));
+}
+
 size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize)
 {
-    DTable_max_t dt;   /* Static analyzer seems unable to understand this table will be properly initialized later */
-    return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG);
+    /* Static analyzer seems unable to understand this table will be properly initialized later */
+    U32 wksp[FSE_DECOMPRESS_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)];
+    return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, FSE_MAX_TABLELOG, wksp, sizeof(wksp));
 }
-
+#endif
 
 
 #endif   /* FSE_COMMONDEFS_ONLY */
index ef43268..3d47ced 100644 (file)
@@ -1,7 +1,7 @@
 /* ******************************************************************
  * huff0 huffman codec,
  * part of Finite State Entropy library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  * You can contact the author at :
  * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -20,7 +20,7 @@ extern "C" {
 #define HUF_H_298734234
 
 /* *** Dependencies *** */
-#include <stddef.h>    /* size_t */
+#include "zstd_deps.h"    /* size_t */
 
 
 /* *** library symbols visibility *** */
@@ -111,6 +111,8 @@ HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity,
 
 /* *** Dependencies *** */
 #include "mem.h"   /* U32 */
+#define FSE_STATIC_LINKING_ONLY
+#include "fse.h"
 
 
 /* *** Constants *** */
@@ -133,12 +135,16 @@ HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity,
 #define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size))   /* Macro version, useful for static allocation */
 
 /* static allocation of HUF's Compression Table */
+/* this is a private definition, just exposed for allocation and strict aliasing purpose. never EVER access its members directly */
+struct HUF_CElt_s {
+  U16  val;
+  BYTE nbBits;
+};   /* typedef'd to HUF_CElt */
+typedef struct HUF_CElt_s HUF_CElt;   /* consider it an incomplete type */
 #define HUF_CTABLE_SIZE_U32(maxSymbolValue)   ((maxSymbolValue)+1)   /* Use tables of U32, for proper alignment */
 #define HUF_CTABLE_SIZE(maxSymbolValue)       (HUF_CTABLE_SIZE_U32(maxSymbolValue) * sizeof(U32))
 #define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
-    U32 name##hb[HUF_CTABLE_SIZE_U32(maxSymbolValue)]; \
-    void* name##hv = &(name##hb); \
-    HUF_CElt* name = (HUF_CElt*)(name##hv)   /* no final ; */
+    HUF_CElt name[HUF_CTABLE_SIZE_U32(maxSymbolValue)] /* no final ; */
 
 /* static allocation of HUF's DTable */
 typedef U32 HUF_DTable;
@@ -184,9 +190,9 @@ size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
  *  or to save and regenerate 'CTable' using external methods.
  */
 unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
-typedef struct HUF_CElt_s HUF_CElt;   /* incomplete type */
 size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits);   /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */
 size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
+size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize);
 size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
 size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
 int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
@@ -226,6 +232,19 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize,
                      U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
                      const void* src, size_t srcSize);
 
+/*! HUF_readStats_wksp() :
+ * Same as HUF_readStats() but takes an external workspace which must be
+ * 4-byte aligned and its size must be >= HUF_READ_STATS_WORKSPACE_SIZE.
+ * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
+ */
+#define HUF_READ_STATS_WORKSPACE_SIZE_U32 FSE_DECOMPRESS_WKSP_SIZE_U32(6, HUF_TABLELOG_MAX-1)
+#define HUF_READ_STATS_WORKSPACE_SIZE (HUF_READ_STATS_WORKSPACE_SIZE_U32 * sizeof(unsigned))
+size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize,
+                          U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
+                          const void* src, size_t srcSize,
+                          void* workspace, size_t wkspSize,
+                          int bmi2);
+
 /** HUF_readCTable() :
  *  Loading a CTable saved with HUF_writeCTable() */
 size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights);
@@ -260,7 +279,7 @@ U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
  *  a required workspace size greater than that specified in the following
  *  macro.
  */
-#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10)
+#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9))
 #define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
 
 #ifndef HUF_FORCE_DECOMPRESS_X2
@@ -332,6 +351,9 @@ size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstS
 #endif
 size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
 size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_readDTableX1_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2);
+#endif
 
 #endif /* HUF_STATIC_LINKING_ONLY */
 
index c3f98fc..9f3b81a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -18,8 +18,10 @@ extern "C" {
 /*-****************************************
 *  Dependencies
 ******************************************/
-#include <stddef.h>     /* size_t, ptrdiff_t */
-#include <string.h>     /* memcpy */
+#include <stddef.h>  /* size_t, ptrdiff_t */
+#include "compiler.h"  /* __has_builtin */
+#include "debug.h"  /* DEBUG_STATIC_ASSERT */
+#include "zstd_deps.h"  /* ZSTD_memcpy */
 
 
 /*-****************************************
@@ -39,93 +41,15 @@ extern "C" {
 #  define MEM_STATIC static  /* this version may generate warnings for unused static functions; disable the relevant warning */
 #endif
 
-#ifndef __has_builtin
-#  define __has_builtin(x) 0  /* compat. with non-clang compilers */
-#endif
-
-/* code only tested on 32 and 64 bits systems */
-#define MEM_STATIC_ASSERT(c)   { enum { MEM_static_assert = 1/(int)(!!(c)) }; }
-MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
-
-/* detects whether we are being compiled under msan */
-#if defined (__has_feature)
-#  if __has_feature(memory_sanitizer)
-#    define MEMORY_SANITIZER 1
-#  endif
-#endif
-
-#if defined (MEMORY_SANITIZER)
-/* Not all platforms that support msan provide sanitizers/msan_interface.h.
- * We therefore declare the functions we need ourselves, rather than trying to
- * include the header file... */
-
-#include <stdint.h> /* intptr_t */
-
-/* Make memory region fully initialized (without changing its contents). */
-void __msan_unpoison(const volatile void *a, size_t size);
-
-/* Make memory region fully uninitialized (without changing its contents).
-   This is a legacy interface that does not update origin information. Use
-   __msan_allocated_memory() instead. */
-void __msan_poison(const volatile void *a, size_t size);
-
-/* Returns the offset of the first (at least partially) poisoned byte in the
-   memory range, or -1 if the whole range is good. */
-intptr_t __msan_test_shadow(const volatile void *x, size_t size);
-#endif
-
-/* detects whether we are being compiled under asan */
-#if defined (__has_feature)
-#  if __has_feature(address_sanitizer)
-#    define ADDRESS_SANITIZER 1
-#  endif
-#elif defined(__SANITIZE_ADDRESS__)
-#  define ADDRESS_SANITIZER 1
-#endif
-
-#if defined (ADDRESS_SANITIZER)
-/* Not all platforms that support asan provide sanitizers/asan_interface.h.
- * We therefore declare the functions we need ourselves, rather than trying to
- * include the header file... */
-
-/**
- * Marks a memory region (<c>[addr, addr+size)</c>) as unaddressable.
- *
- * This memory must be previously allocated by your program. Instrumented
- * code is forbidden from accessing addresses in this region until it is
- * unpoisoned. This function is not guaranteed to poison the entire region -
- * it could poison only a subregion of <c>[addr, addr+size)</c> due to ASan
- * alignment restrictions.
- *
- * \note This function is not thread-safe because no two threads can poison or
- * unpoison memory in the same memory region simultaneously.
- *
- * \param addr Start of memory region.
- * \param size Size of memory region. */
-void __asan_poison_memory_region(void const volatile *addr, size_t size);
-
-/**
- * Marks a memory region (<c>[addr, addr+size)</c>) as addressable.
- *
- * This memory must be previously allocated by your program. Accessing
- * addresses in this region is allowed until this region is poisoned again.
- * This function could unpoison a super-region of <c>[addr, addr+size)</c> due
- * to ASan alignment restrictions.
- *
- * \note This function is not thread-safe because no two threads can
- * poison or unpoison memory in the same memory region simultaneously.
- *
- * \param addr Start of memory region.
- * \param size Size of memory region. */
-void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
-#endif
-
-
 /*-**************************************************************
 *  Basic Types
 *****************************************************************/
 #if  !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
-# include <stdint.h>
+#  if defined(_AIX)
+#    include <inttypes.h>
+#  else
+#    include <stdint.h> /* intptr_t */
+#  endif
   typedef   uint8_t BYTE;
   typedef  uint16_t U16;
   typedef   int16_t S16;
@@ -157,7 +81,53 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
 
 
 /*-**************************************************************
-*  Memory I/O
+*  Memory I/O API
+*****************************************************************/
+/*=== Static platform detection ===*/
+MEM_STATIC unsigned MEM_32bits(void);
+MEM_STATIC unsigned MEM_64bits(void);
+MEM_STATIC unsigned MEM_isLittleEndian(void);
+
+/*=== Native unaligned read/write ===*/
+MEM_STATIC U16 MEM_read16(const void* memPtr);
+MEM_STATIC U32 MEM_read32(const void* memPtr);
+MEM_STATIC U64 MEM_read64(const void* memPtr);
+MEM_STATIC size_t MEM_readST(const void* memPtr);
+
+MEM_STATIC void MEM_write16(void* memPtr, U16 value);
+MEM_STATIC void MEM_write32(void* memPtr, U32 value);
+MEM_STATIC void MEM_write64(void* memPtr, U64 value);
+
+/*=== Little endian unaligned read/write ===*/
+MEM_STATIC U16 MEM_readLE16(const void* memPtr);
+MEM_STATIC U32 MEM_readLE24(const void* memPtr);
+MEM_STATIC U32 MEM_readLE32(const void* memPtr);
+MEM_STATIC U64 MEM_readLE64(const void* memPtr);
+MEM_STATIC size_t MEM_readLEST(const void* memPtr);
+
+MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val);
+MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val);
+MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32);
+MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64);
+MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val);
+
+/*=== Big endian unaligned read/write ===*/
+MEM_STATIC U32 MEM_readBE32(const void* memPtr);
+MEM_STATIC U64 MEM_readBE64(const void* memPtr);
+MEM_STATIC size_t MEM_readBEST(const void* memPtr);
+
+MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32);
+MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64);
+MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val);
+
+/*=== Byteswap ===*/
+MEM_STATIC U32 MEM_swap32(U32 in);
+MEM_STATIC U64 MEM_swap64(U64 in);
+MEM_STATIC size_t MEM_swapST(size_t in);
+
+
+/*-**************************************************************
+*  Memory I/O Implementation
 *****************************************************************/
 /* MEM_FORCE_MEMORY_ACCESS :
  * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
@@ -234,37 +204,37 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v =
 
 MEM_STATIC U16 MEM_read16(const void* memPtr)
 {
-    U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
+    U16 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;
 }
 
 MEM_STATIC U32 MEM_read32(const void* memPtr)
 {
-    U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
+    U32 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;
 }
 
 MEM_STATIC U64 MEM_read64(const void* memPtr)
 {
-    U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
+    U64 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;
 }
 
 MEM_STATIC size_t MEM_readST(const void* memPtr)
 {
-    size_t val; memcpy(&val, memPtr, sizeof(val)); return val;
+    size_t val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;
 }
 
 MEM_STATIC void MEM_write16(void* memPtr, U16 value)
 {
-    memcpy(memPtr, &value, sizeof(value));
+    ZSTD_memcpy(memPtr, &value, sizeof(value));
 }
 
 MEM_STATIC void MEM_write32(void* memPtr, U32 value)
 {
-    memcpy(memPtr, &value, sizeof(value));
+    ZSTD_memcpy(memPtr, &value, sizeof(value));
 }
 
 MEM_STATIC void MEM_write64(void* memPtr, U64 value)
 {
-    memcpy(memPtr, &value, sizeof(value));
+    ZSTD_memcpy(memPtr, &value, sizeof(value));
 }
 
 #endif /* MEM_FORCE_MEMORY_ACCESS */
@@ -336,7 +306,7 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
 
 MEM_STATIC U32 MEM_readLE24(const void* memPtr)
 {
-    return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
+    return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16);
 }
 
 MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
@@ -443,6 +413,9 @@ MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
         MEM_writeBE64(memPtr, (U64)val);
 }
 
+/* code only tested on 32 and 64 bits systems */
+MEM_STATIC void MEM_check(void) { DEBUG_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
+
 
 #if defined (__cplusplus)
 }
index aa4b4de..ea70b8b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -10,9 +10,9 @@
 
 
 /* ======   Dependencies   ======= */
-#include <stddef.h>    /* size_t */
+#include "zstd_deps.h" /* size_t */
 #include "debug.h"     /* assert */
-#include "zstd_internal.h"  /* ZSTD_malloc, ZSTD_free */
+#include "zstd_internal.h"  /* ZSTD_customMalloc, ZSTD_customFree */
 #include "pool.h"
 
 /* ======   Compiler specifics   ====== */
@@ -105,6 +105,10 @@ static void* POOL_thread(void* opaque) {
     assert(0);  /* Unreachable */
 }
 
+POOL_ctx* ZSTD_createThreadPool(size_t numThreads) {
+    return POOL_create (numThreads, 0);
+}
+
 POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
     return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
 }
@@ -115,14 +119,14 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
     /* Check parameters */
     if (!numThreads) { return NULL; }
     /* Allocate the context and zero initialize */
-    ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem);
+    ctx = (POOL_ctx*)ZSTD_customCalloc(sizeof(POOL_ctx), customMem);
     if (!ctx) { return NULL; }
     /* Initialize the job queue.
      * It needs one extra space since one space is wasted to differentiate
      * empty and full queues.
      */
     ctx->queueSize = queueSize + 1;
-    ctx->queue = (POOL_job*)ZSTD_malloc(ctx->queueSize * sizeof(POOL_job), customMem);
+    ctx->queue = (POOL_job*)ZSTD_customMalloc(ctx->queueSize * sizeof(POOL_job), customMem);
     ctx->queueHead = 0;
     ctx->queueTail = 0;
     ctx->numThreadsBusy = 0;
@@ -136,7 +140,7 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
     }
     ctx->shutdown = 0;
     /* Allocate space for the thread handles */
-    ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem);
+    ctx->threads = (ZSTD_pthread_t*)ZSTD_customMalloc(numThreads * sizeof(ZSTD_pthread_t), customMem);
     ctx->threadCapacity = 0;
     ctx->customMem = customMem;
     /* Check for errors */
@@ -179,12 +183,14 @@ void POOL_free(POOL_ctx *ctx) {
     ZSTD_pthread_mutex_destroy(&ctx->queueMutex);
     ZSTD_pthread_cond_destroy(&ctx->queuePushCond);
     ZSTD_pthread_cond_destroy(&ctx->queuePopCond);
-    ZSTD_free(ctx->queue, ctx->customMem);
-    ZSTD_free(ctx->threads, ctx->customMem);
-    ZSTD_free(ctx, ctx->customMem);
+    ZSTD_customFree(ctx->queue, ctx->customMem);
+    ZSTD_customFree(ctx->threads, ctx->customMem);
+    ZSTD_customFree(ctx, ctx->customMem);
 }
 
-
+void ZSTD_freeThreadPool (ZSTD_threadPool* pool) {
+  POOL_free (pool);
+}
 
 size_t POOL_sizeof(POOL_ctx *ctx) {
     if (ctx==NULL) return 0;  /* supports sizeof NULL */
@@ -203,11 +209,11 @@ static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads)
         return 0;
     }
     /* numThreads > threadCapacity */
-    {   ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem);
+    {   ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customMalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem);
         if (!threadPool) return 1;
         /* replace existing thread pool */
-        memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool));
-        ZSTD_free(ctx->threads, ctx->customMem);
+        ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool));
+        ZSTD_customFree(ctx->threads, ctx->customMem);
         ctx->threads = threadPool;
         /* Initialize additional threads */
         {   size_t threadId;
@@ -301,7 +307,7 @@ int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque)
 struct POOL_ctx_s {
     int dummy;
 };
-static POOL_ctx g_ctx;
+static POOL_ctx g_poolCtx;
 
 POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
     return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
@@ -311,11 +317,11 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
     (void)numThreads;
     (void)queueSize;
     (void)customMem;
-    return &g_ctx;
+    return &g_poolCtx;
 }
 
 void POOL_free(POOL_ctx* ctx) {
-    assert(!ctx || ctx == &g_ctx);
+    assert(!ctx || ctx == &g_poolCtx);
     (void)ctx;
 }
 
@@ -337,7 +343,7 @@ int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) {
 
 size_t POOL_sizeof(POOL_ctx* ctx) {
     if (ctx==NULL) return 0;  /* supports sizeof NULL */
-    assert(ctx == &g_ctx);
+    assert(ctx == &g_poolCtx);
     return sizeof(*ctx);
 }
 
index 259bafc..e18aa07 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -16,7 +16,7 @@ extern "C" {
 #endif
 
 
-#include <stddef.h>   /* size_t */
+#include "zstd_deps.h"
 #define ZSTD_STATIC_LINKING_ONLY   /* ZSTD_customMem */
 #include "../zstd.h"
 
index e2edb31..92cf57c 100644 (file)
@@ -78,11 +78,12 @@ int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr)
 
 #if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32)
 
-#include <stdlib.h>
+#define ZSTD_DEPS_NEED_MALLOC
+#include "zstd_deps.h"
 
 int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr)
 {
-    *mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+    *mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t));
     if (!*mutex)
         return 1;
     return pthread_mutex_init(*mutex, attr);
@@ -94,14 +95,14 @@ int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex)
         return 0;
     {
         int const ret = pthread_mutex_destroy(*mutex);
-        free(*mutex);
+        ZSTD_free(*mutex);
         return ret;
     }
 }
 
 int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr)
 {
-    *cond = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
+    *cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t));
     if (!*cond)
         return 1;
     return pthread_cond_init(*cond, attr);
@@ -113,7 +114,7 @@ int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond)
         return 0;
     {
         int const ret = pthread_cond_destroy(*cond);
-        free(*cond);
+        ZSTD_free(*cond);
         return ret;
     }
 }
index 3d7655e..926b336 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  xxHash - Fast Hash algorithm
- *  Copyright (c) 2012-2020, Yann Collet, Facebook, Inc.
+ *  Copyright (c) Yann Collet, Facebook, Inc.
  *
  *  You can contact the author at :
  *  - xxHash homepage: http://www.xxhash.com
 *  Includes & Memory related functions
 ***************************************/
 /* Modify the local functions below should you wish to use some other memory routines */
-/* for malloc(), free() */
-#include <stdlib.h>
-#include <stddef.h>     /* size_t */
-static void* XXH_malloc(size_t s) { return malloc(s); }
-static void  XXH_free  (void* p)  { free(p); }
-/* for memcpy() */
-#include <string.h>
-static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
+/* for ZSTD_malloc(), ZSTD_free() */
+#define ZSTD_DEPS_NEED_MALLOC
+#include "zstd_deps.h"  /* size_t, ZSTD_malloc, ZSTD_free, ZSTD_memcpy */
+static void* XXH_malloc(size_t s) { return ZSTD_malloc(s); }
+static void  XXH_free  (void* p)  { ZSTD_free(p); }
+static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_memcpy(dest,src,size); }
 
 #ifndef XXH_STATIC_LINKING_ONLY
 #  define XXH_STATIC_LINKING_ONLY
@@ -93,49 +91,13 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcp
 /* *************************************
 *  Compiler Specific Options
 ***************************************/
-#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */
-#  define INLINE_KEYWORD inline
-#else
-#  define INLINE_KEYWORD
-#endif
-
-#if defined(__GNUC__) || defined(__ICCARM__)
-#  define FORCE_INLINE_ATTR __attribute__((always_inline))
-#elif defined(_MSC_VER)
-#  define FORCE_INLINE_ATTR __forceinline
-#else
-#  define FORCE_INLINE_ATTR
-#endif
-
-#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
-
-
-#ifdef _MSC_VER
-#  pragma warning(disable : 4127)      /* disable: C4127: conditional expression is constant */
-#endif
+#include "compiler.h"
 
 
 /* *************************************
 *  Basic Types
 ***************************************/
-#ifndef MEM_MODULE
-# define MEM_MODULE
-# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
-#   include <stdint.h>
-    typedef uint8_t  BYTE;
-    typedef uint16_t U16;
-    typedef uint32_t U32;
-    typedef  int32_t S32;
-    typedef uint64_t U64;
-#  else
-    typedef unsigned char      BYTE;
-    typedef unsigned short     U16;
-    typedef unsigned int       U32;
-    typedef   signed int       S32;
-    typedef unsigned long long U64;   /* if your compiler doesn't support unsigned long long, replace by another 64-bit type here. Note that xxhash.h will also need to be updated. */
-#  endif
-#endif
-
+#include "mem.h"  /* BYTE, U32, U64, size_t */
 
 #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
 
@@ -161,14 +123,14 @@ static U64 XXH_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
 static U32 XXH_read32(const void* memPtr)
 {
     U32 val;
-    memcpy(&val, memPtr, sizeof(val));
+    ZSTD_memcpy(&val, memPtr, sizeof(val));
     return val;
 }
 
 static U64 XXH_read64(const void* memPtr)
 {
     U64 val;
-    memcpy(&val, memPtr, sizeof(val));
+    ZSTD_memcpy(&val, memPtr, sizeof(val));
     return val;
 }
 
@@ -305,12 +267,12 @@ XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
 ****************************/
 XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dstState, const XXH32_state_t* restrict srcState)
 {
-    memcpy(dstState, srcState, sizeof(*dstState));
+    ZSTD_memcpy(dstState, srcState, sizeof(*dstState));
 }
 
 XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dstState, const XXH64_state_t* restrict srcState)
 {
-    memcpy(dstState, srcState, sizeof(*dstState));
+    ZSTD_memcpy(dstState, srcState, sizeof(*dstState));
 }
 
 
@@ -552,12 +514,12 @@ XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
 XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
 {
     XXH32_state_t state;   /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
-    memset(&state, 0, sizeof(state)-4);   /* do not write into reserved, for future removal */
+    ZSTD_memset(&state, 0, sizeof(state)-4);   /* do not write into reserved, for future removal */
     state.v1 = seed + PRIME32_1 + PRIME32_2;
     state.v2 = seed + PRIME32_2;
     state.v3 = seed + 0;
     state.v4 = seed - PRIME32_1;
-    memcpy(statePtr, &state, sizeof(state));
+    ZSTD_memcpy(statePtr, &state, sizeof(state));
     return XXH_OK;
 }
 
@@ -565,12 +527,12 @@ XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int s
 XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
 {
     XXH64_state_t state;   /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
-    memset(&state, 0, sizeof(state)-8);   /* do not write into reserved, for future removal */
+    ZSTD_memset(&state, 0, sizeof(state)-8);   /* do not write into reserved, for future removal */
     state.v1 = seed + PRIME64_1 + PRIME64_2;
     state.v2 = seed + PRIME64_2;
     state.v3 = seed + 0;
     state.v4 = seed - PRIME64_1;
-    memcpy(statePtr, &state, sizeof(state));
+    ZSTD_memcpy(statePtr, &state, sizeof(state));
     return XXH_OK;
 }
 
@@ -841,14 +803,14 @@ XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t
 {
     XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
     if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
-    memcpy(dst, &hash, sizeof(*dst));
+    ZSTD_memcpy(dst, &hash, sizeof(*dst));
 }
 
 XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
 {
     XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
     if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
-    memcpy(dst, &hash, sizeof(*dst));
+    ZSTD_memcpy(dst, &hash, sizeof(*dst));
 }
 
 XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
index 4207eba..16c1f16 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * xxHash - Extremely Fast Hash algorithm
  * Header File
- * Copyright (c) 2012-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  * You can contact the author at :
  * - xxHash source repository : https://github.com/Cyan4973/xxHash
@@ -55,7 +55,7 @@ extern "C" {
 /* ****************************
 *  Definitions
 ******************************/
-#include <stddef.h>   /* size_t */
+#include "zstd_deps.h"
 typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
 
 
index 91fe332..3d7e35b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -13,8 +13,8 @@
 /*-*************************************
 *  Dependencies
 ***************************************/
-#include <stdlib.h>      /* malloc, calloc, free */
-#include <string.h>      /* memset */
+#define ZSTD_DEPS_NEED_MALLOC
+#include "zstd_deps.h"   /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */
 #include "error_private.h"
 #include "zstd_internal.h"
 
@@ -53,31 +53,31 @@ const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString
 /*=**************************************************************
 *  Custom allocator
 ****************************************************************/
-void* ZSTD_malloc(size_t size, ZSTD_customMem customMem)
+void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem)
 {
     if (customMem.customAlloc)
         return customMem.customAlloc(customMem.opaque, size);
-    return malloc(size);
+    return ZSTD_malloc(size);
 }
 
-void* ZSTD_calloc(size_t size, ZSTD_customMem customMem)
+void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem)
 {
     if (customMem.customAlloc) {
         /* calloc implemented as malloc+memset;
          * not as efficient as calloc, but next best guess for custom malloc */
         void* const ptr = customMem.customAlloc(customMem.opaque, size);
-        memset(ptr, 0, size);
+        ZSTD_memset(ptr, 0, size);
         return ptr;
     }
-    return calloc(1, size);
+    return ZSTD_calloc(1, size);
 }
 
-void ZSTD_free(void* ptr, ZSTD_customMem customMem)
+void ZSTD_customFree(void* ptr, ZSTD_customMem customMem)
 {
     if (ptr!=NULL) {
         if (customMem.customFree)
             customMem.customFree(customMem.opaque, ptr);
         else
-            free(ptr);
+            ZSTD_free(ptr);
     }
 }
diff --git a/Utilities/cmzstd/lib/common/zstd_deps.h b/Utilities/cmzstd/lib/common/zstd_deps.h
new file mode 100644 (file)
index 0000000..1421134
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* This file provides common libc dependencies that zstd requires.
+ * The purpose is to allow replacing this file with a custom implementation
+ * to compile zstd without libc support.
+ */
+
+/* Need:
+ * NULL
+ * INT_MAX
+ * UINT_MAX
+ * ZSTD_memcpy()
+ * ZSTD_memset()
+ * ZSTD_memmove()
+ */
+#ifndef ZSTD_DEPS_COMMON
+#define ZSTD_DEPS_COMMON
+
+#include <limits.h>
+#include <stddef.h>
+#include <string.h>
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define ZSTD_memcpy(d,s,l) __builtin_memcpy((d),(s),(l))
+# define ZSTD_memmove(d,s,l) __builtin_memmove((d),(s),(l))
+# define ZSTD_memset(p,v,l) __builtin_memset((p),(v),(l))
+#else
+# define ZSTD_memcpy(d,s,l) memcpy((d),(s),(l))
+# define ZSTD_memmove(d,s,l) memmove((d),(s),(l))
+# define ZSTD_memset(p,v,l) memset((p),(v),(l))
+#endif
+
+#endif /* ZSTD_DEPS_COMMON */
+
+/* Need:
+ * ZSTD_malloc()
+ * ZSTD_free()
+ * ZSTD_calloc()
+ */
+#ifdef ZSTD_DEPS_NEED_MALLOC
+#ifndef ZSTD_DEPS_MALLOC
+#define ZSTD_DEPS_MALLOC
+
+#include <stdlib.h>
+
+#define ZSTD_malloc(s) malloc(s)
+#define ZSTD_calloc(n,s) calloc((n), (s))
+#define ZSTD_free(p) free((p))
+
+#endif /* ZSTD_DEPS_MALLOC */
+#endif /* ZSTD_DEPS_NEED_MALLOC */
+
+/*
+ * Provides 64-bit math support.
+ * Need:
+ * U64 ZSTD_div64(U64 dividend, U32 divisor)
+ */
+#ifdef ZSTD_DEPS_NEED_MATH64
+#ifndef ZSTD_DEPS_MATH64
+#define ZSTD_DEPS_MATH64
+
+#define ZSTD_div64(dividend, divisor) ((dividend) / (divisor))
+
+#endif /* ZSTD_DEPS_MATH64 */
+#endif /* ZSTD_DEPS_NEED_MATH64 */
+
+/* Need:
+ * assert()
+ */
+#ifdef ZSTD_DEPS_NEED_ASSERT
+#ifndef ZSTD_DEPS_ASSERT
+#define ZSTD_DEPS_ASSERT
+
+#include <assert.h>
+
+#endif /* ZSTD_DEPS_ASSERT */
+#endif /* ZSTD_DEPS_NEED_ASSERT */
+
+/* Need:
+ * ZSTD_DEBUG_PRINT()
+ */
+#ifdef ZSTD_DEPS_NEED_IO
+#ifndef ZSTD_DEPS_IO
+#define ZSTD_DEPS_IO
+
+#include <stdio.h>
+#define ZSTD_DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)
+
+#endif /* ZSTD_DEPS_IO */
+#endif /* ZSTD_DEPS_NEED_IO */
+
+/* Only requested when <stdint.h> is known to be present.
+ * Need:
+ * intptr_t
+ */
+#ifdef ZSTD_DEPS_NEED_STDINT
+#ifndef ZSTD_DEPS_STDINT
+#define ZSTD_DEPS_STDINT
+
+#include <stdint.h>
+
+#endif /* ZSTD_DEPS_STDINT */
+#endif /* ZSTD_DEPS_NEED_STDINT */
index 3bc7e55..68252e9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -19,7 +19,7 @@
 /*-*************************************
 *  Dependencies
 ***************************************/
-#ifdef __aarch64__
+#if !defined(ZSTD_NO_INTRINSICS) && defined(__ARM_NEON)
 #include <arm_neon.h>
 #endif
 #include "compiler.h"
 #  define XXH_STATIC_LINKING_ONLY  /* XXH64_state_t */
 #endif
 #include "xxhash.h"                /* XXH_reset, update, digest */
+#ifndef ZSTD_NO_TRACE
+#  include "zstd_trace.h"
+#else
+#  define ZSTD_TRACE 0
+#endif
 
 #if defined (__cplusplus)
 extern "C" {
@@ -139,7 +144,7 @@ void _force_has_format_string(const char *format, ...) {
 
 #define ZSTD_REP_NUM      3                 /* number of repcodes */
 #define ZSTD_REP_MOVE     (ZSTD_REP_NUM-1)
-static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
+static UNUSED_ATTR const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
 
 #define KB *(1 <<10)
 #define MB *(1 <<20)
@@ -153,13 +158,13 @@ static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
 #define BIT0   1
 
 #define ZSTD_WINDOWLOG_ABSOLUTEMIN 10
-static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };
-static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };
+static UNUSED_ATTR const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };
+static UNUSED_ATTR const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };
 
 #define ZSTD_FRAMEIDSIZE 4   /* magic number size */
 
 #define ZSTD_BLOCKHEADERSIZE 3   /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
-static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
+static UNUSED_ATTR const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
 typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
 
 #define ZSTD_FRAMECHECKSUMSIZE 4
@@ -186,61 +191,75 @@ typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingTy
 #define OffFSELog   8
 #define MaxFSELog  MAX(MAX(MLFSELog, LLFSELog), OffFSELog)
 
-static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0,
-                                      0, 0, 0, 0, 0, 0, 0, 0,
-                                      1, 1, 1, 1, 2, 2, 3, 3,
-                                      4, 6, 7, 8, 9,10,11,12,
-                                     13,14,15,16 };
-static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2,
-                                             2, 2, 2, 2, 2, 1, 1, 1,
-                                             2, 2, 2, 2, 2, 2, 2, 2,
-                                             2, 3, 2, 1, 1, 1, 1, 1,
-                                            -1,-1,-1,-1 };
+#define ZSTD_MAX_HUF_HEADER_SIZE 128 /* header + <= 127 byte tree description */
+/* Each table cannot take more than #symbols * FSELog bits */
+#define ZSTD_MAX_FSE_HEADERS_SIZE (((MaxML + 1) * MLFSELog + (MaxLL + 1) * LLFSELog + (MaxOff + 1) * OffFSELog + 7) / 8)
+
+static UNUSED_ATTR const U32 LL_bits[MaxLL+1] = {
+     0, 0, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0,
+     1, 1, 1, 1, 2, 2, 3, 3,
+     4, 6, 7, 8, 9,10,11,12,
+    13,14,15,16
+};
+static UNUSED_ATTR const S16 LL_defaultNorm[MaxLL+1] = {
+     4, 3, 2, 2, 2, 2, 2, 2,
+     2, 2, 2, 2, 2, 1, 1, 1,
+     2, 2, 2, 2, 2, 2, 2, 2,
+     2, 3, 2, 1, 1, 1, 1, 1,
+    -1,-1,-1,-1
+};
 #define LL_DEFAULTNORMLOG 6  /* for static allocation */
-static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
-
-static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0,
-                                      0, 0, 0, 0, 0, 0, 0, 0,
-                                      0, 0, 0, 0, 0, 0, 0, 0,
-                                      0, 0, 0, 0, 0, 0, 0, 0,
-                                      1, 1, 1, 1, 2, 2, 3, 3,
-                                      4, 4, 5, 7, 8, 9,10,11,
-                                     12,13,14,15,16 };
-static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2,
-                                             2, 1, 1, 1, 1, 1, 1, 1,
-                                             1, 1, 1, 1, 1, 1, 1, 1,
-                                             1, 1, 1, 1, 1, 1, 1, 1,
-                                             1, 1, 1, 1, 1, 1, 1, 1,
-                                             1, 1, 1, 1, 1, 1,-1,-1,
-                                            -1,-1,-1,-1,-1 };
+static UNUSED_ATTR const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
+
+static UNUSED_ATTR const U32 ML_bits[MaxML+1] = {
+     0, 0, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0,
+     1, 1, 1, 1, 2, 2, 3, 3,
+     4, 4, 5, 7, 8, 9,10,11,
+    12,13,14,15,16
+};
+static UNUSED_ATTR const S16 ML_defaultNorm[MaxML+1] = {
+     1, 4, 3, 2, 2, 2, 2, 2,
+     2, 1, 1, 1, 1, 1, 1, 1,
+     1, 1, 1, 1, 1, 1, 1, 1,
+     1, 1, 1, 1, 1, 1, 1, 1,
+     1, 1, 1, 1, 1, 1, 1, 1,
+     1, 1, 1, 1, 1, 1,-1,-1,
+    -1,-1,-1,-1,-1
+};
 #define ML_DEFAULTNORMLOG 6  /* for static allocation */
-static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
-
-static const S16 OF_defaultNorm[DefaultMaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2,
-                                                     2, 1, 1, 1, 1, 1, 1, 1,
-                                                     1, 1, 1, 1, 1, 1, 1, 1,
-                                                    -1,-1,-1,-1,-1 };
+static UNUSED_ATTR const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
+
+static UNUSED_ATTR const S16 OF_defaultNorm[DefaultMaxOff+1] = {
+     1, 1, 1, 1, 1, 1, 2, 2,
+     2, 1, 1, 1, 1, 1, 1, 1,
+     1, 1, 1, 1, 1, 1, 1, 1,
+    -1,-1,-1,-1,-1
+};
 #define OF_DEFAULTNORMLOG 5  /* for static allocation */
-static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
+static UNUSED_ATTR const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
 
 
 /*-*******************************************
 *  Shared functions to include for inlining
 *********************************************/
 static void ZSTD_copy8(void* dst, const void* src) {
-#ifdef __aarch64__
+#if !defined(ZSTD_NO_INTRINSICS) && defined(__ARM_NEON)
     vst1_u8((uint8_t*)dst, vld1_u8((const uint8_t*)src));
 #else
-    memcpy(dst, src, 8);
+    ZSTD_memcpy(dst, src, 8);
 #endif
 }
 
 #define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
 static void ZSTD_copy16(void* dst, const void* src) {
-#ifdef __aarch64__
+#if !defined(ZSTD_NO_INTRINSICS) && defined(__ARM_NEON)
     vst1q_u8((uint8_t*)dst, vld1q_u8((const uint8_t*)src));
 #else
-    memcpy(dst, src, 16);
+    ZSTD_memcpy(dst, src, 16);
 #endif
 }
 #define COPY16(d,s) { ZSTD_copy16(d,s); d+=16; s+=16; }
@@ -255,13 +274,13 @@ typedef enum {
 } ZSTD_overlap_e;
 
 /*! ZSTD_wildcopy() :
- *  Custom version of memcpy(), can over read/write up to WILDCOPY_OVERLENGTH bytes (if length==0)
+ *  Custom version of ZSTD_memcpy(), can over read/write up to WILDCOPY_OVERLENGTH bytes (if length==0)
  *  @param ovtype controls the overlap detection
  *         - ZSTD_no_overlap: The source and destination are guaranteed to be at least WILDCOPY_VECLEN bytes apart.
  *         - ZSTD_overlap_src_before_dst: The src and dst may overlap, but they MUST be at least 8 bytes apart.
  *           The src buffer must be before the dst buffer.
  */
-MEM_STATIC FORCE_INLINE_ATTR 
+MEM_STATIC FORCE_INLINE_ATTR
 void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e const ovtype)
 {
     ptrdiff_t diff = (BYTE*)dst - (const BYTE*)src;
@@ -284,14 +303,16 @@ void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e
          * one COPY16() in the first call. Then, do two calls per loop since
          * at that point it is more likely to have a high trip count.
          */
-#ifndef __aarch64__
+#ifdef __aarch64__
         do {
             COPY16(op, ip);
         }
         while (op < oend);
 #else
-        COPY16(op, ip);
-        if (op >= oend) return;
+        ZSTD_copy16(op, ip);
+        if (16 >= length) return;
+        op += 16;
+        ip += 16;
         do {
             COPY16(op, ip);
             COPY16(op, ip);
@@ -305,7 +326,7 @@ MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src,
 {
     size_t const length = MIN(dstCapacity, srcSize);
     if (length > 0) {
-        memcpy(dst, src, length);
+        ZSTD_memcpy(dst, src, length);
     }
     return length;
 }
@@ -320,28 +341,46 @@ MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src,
  * In which case, resize it down to free some memory */
 #define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128
 
+/* Controls whether the input/output buffer is buffered or stable. */
+typedef enum {
+    ZSTD_bm_buffered = 0,  /* Buffer the input/output */
+    ZSTD_bm_stable = 1     /* ZSTD_inBuffer/ZSTD_outBuffer is stable */
+} ZSTD_bufferMode_e;
+
 
 /*-*******************************************
 *  Private declarations
 *********************************************/
 typedef struct seqDef_s {
-    U32 offset;
+    U32 offset;         /* offset == rawOffset + ZSTD_REP_NUM, or equivalently, offCode + 1 */
     U16 litLength;
     U16 matchLength;
 } seqDef;
 
+/* Controls whether seqStore has a single "long" litLength or matchLength. See seqStore_t. */
+typedef enum {
+    ZSTD_llt_none = 0,             /* no longLengthType */
+    ZSTD_llt_literalLength = 1,    /* represents a long literal */
+    ZSTD_llt_matchLength = 2       /* represents a long match */
+} ZSTD_longLengthType_e;
+
 typedef struct {
     seqDef* sequencesStart;
-    seqDef* sequences;
+    seqDef* sequences;      /* ptr to end of sequences */
     BYTE* litStart;
-    BYTE* lit;
+    BYTE* lit;              /* ptr to end of literals */
     BYTE* llCode;
     BYTE* mlCode;
     BYTE* ofCode;
     size_t maxNbSeq;
     size_t maxNbLit;
-    U32   longLengthID;   /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
-    U32   longLengthPos;
+
+    /* longLengthPos and longLengthType to allow us to represent either a single litLength or matchLength
+     * in the seqStore that has a value larger than U16 (if it exists). To do so, we increment
+     * the existing value of the litLength or matchLength by 0x10000.
+     */
+    ZSTD_longLengthType_e   longLengthType;
+    U32                     longLengthPos;  /* Index of the sequence to apply long length modification to */
 } seqStore_t;
 
 typedef struct {
@@ -351,7 +390,7 @@ typedef struct {
 
 /**
  * Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences
- * indicated by longLengthPos and longLengthID, and adds MINMATCH back to matchLength.
+ * indicated by longLengthPos and longLengthType, and adds MINMATCH back to matchLength.
  */
 MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq)
 {
@@ -359,10 +398,10 @@ MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore
     seqLen.litLength = seq->litLength;
     seqLen.matchLength = seq->matchLength + MINMATCH;
     if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) {
-        if (seqStore->longLengthID == 1) {
+        if (seqStore->longLengthType == ZSTD_llt_literalLength) {
             seqLen.litLength += 0xFFFF;
         }
-        if (seqStore->longLengthID == 2) {
+        if (seqStore->longLengthType == ZSTD_llt_matchLength) {
             seqLen.matchLength += 0xFFFF;
         }
     }
@@ -384,9 +423,9 @@ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx);   /* compress & dictBu
 void ZSTD_seqToCodes(const seqStore_t* seqStorePtr);   /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */
 
 /* custom memory allocation functions */
-void* ZSTD_malloc(size_t size, ZSTD_customMem customMem);
-void* ZSTD_calloc(size_t size, ZSTD_customMem customMem);
-void ZSTD_free(void* ptr, ZSTD_customMem customMem);
+void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem);
+void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem);
+void ZSTD_customFree(void* ptr, ZSTD_customMem customMem);
 
 
 MEM_STATIC U32 ZSTD_highbit32(U32 val)   /* compress, dictBuilder, decodeCorpus */
@@ -394,8 +433,12 @@ MEM_STATIC U32 ZSTD_highbit32(U32 val)   /* compress, dictBuilder, decodeCorpus
     assert(val != 0);
     {
 #   if defined(_MSC_VER)   /* Visual */
-        unsigned long r=0;
-        return _BitScanReverse(&r, val) ? (unsigned)r : 0;
+#       if STATIC_BMI2 == 1
+            return _lzcnt_u32(val)^31;
+#       else
+            unsigned long r=0;
+            return _BitScanReverse(&r, val) ? (unsigned)r : 0;
+#       endif
 #   elif defined(__GNUC__) && (__GNUC__ >= 3)   /* GCC Intrinsic */
         return __builtin_clz (val) ^ 31;
 #   elif defined(__ICCARM__)    /* IAR Intrinsic */
diff --git a/Utilities/cmzstd/lib/common/zstd_trace.h b/Utilities/cmzstd/lib/common/zstd_trace.h
new file mode 100644 (file)
index 0000000..485cadf
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_TRACE_H
+#define ZSTD_TRACE_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include <stddef.h>
+
+/* weak symbol support */
+#if !defined(ZSTD_HAVE_WEAK_SYMBOLS) && defined(__GNUC__) && \
+    !defined(__APPLE__) && !defined(_WIN32) && !defined(__MINGW32__) && \
+    !defined(__CYGWIN__) && !defined(_AIX)
+#  define ZSTD_HAVE_WEAK_SYMBOLS 1
+#else
+#  define ZSTD_HAVE_WEAK_SYMBOLS 0
+#endif
+#if ZSTD_HAVE_WEAK_SYMBOLS
+#  define ZSTD_WEAK_ATTR __attribute__((__weak__))
+#else
+#  define ZSTD_WEAK_ATTR
+#endif
+
+/* Only enable tracing when weak symbols are available. */
+#ifndef ZSTD_TRACE
+#  define ZSTD_TRACE ZSTD_HAVE_WEAK_SYMBOLS
+#endif
+
+#if ZSTD_TRACE
+
+struct ZSTD_CCtx_s;
+struct ZSTD_DCtx_s;
+struct ZSTD_CCtx_params_s;
+
+typedef struct {
+    /**
+     * ZSTD_VERSION_NUMBER
+     *
+     * This is guaranteed to be the first member of ZSTD_trace.
+     * Otherwise, this struct is not stable between versions. If
+     * the version number does not match your expectation, you
+     * should not interpret the rest of the struct.
+     */
+    unsigned version;
+    /**
+     * Non-zero if streaming (de)compression is used.
+     */
+    unsigned streaming;
+    /**
+     * The dictionary ID.
+     */
+    unsigned dictionaryID;
+    /**
+     * Is the dictionary cold?
+     * Only set on decompression.
+     */
+    unsigned dictionaryIsCold;
+    /**
+     * The dictionary size or zero if no dictionary.
+     */
+    size_t dictionarySize;
+    /**
+     * The uncompressed size of the data.
+     */
+    size_t uncompressedSize;
+    /**
+     * The compressed size of the data.
+     */
+    size_t compressedSize;
+    /**
+     * The fully resolved CCtx parameters (NULL on decompression).
+     */
+    struct ZSTD_CCtx_params_s const* params;
+    /**
+     * The ZSTD_CCtx pointer (NULL on decompression).
+     */
+    struct ZSTD_CCtx_s const* cctx;
+    /**
+     * The ZSTD_DCtx pointer (NULL on compression).
+     */
+    struct ZSTD_DCtx_s const* dctx;
+} ZSTD_Trace;
+
+/**
+ * A tracing context. It must be 0 when tracing is disabled.
+ * Otherwise, any non-zero value returned by a tracing begin()
+ * function is presented to any subsequent calls to end().
+ *
+ * Any non-zero value is treated as tracing is enabled and not
+ * interpreted by the library.
+ *
+ * Two possible uses are:
+ * * A timestamp for when the begin() function was called.
+ * * A unique key identifying the (de)compression, like the
+ *   address of the [dc]ctx pointer if you need to track
+ *   more information than just a timestamp.
+ */
+typedef unsigned long long ZSTD_TraceCtx;
+
+/**
+ * Trace the beginning of a compression call.
+ * @param cctx The dctx pointer for the compression.
+ *             It can be used as a key to map begin() to end().
+ * @returns Non-zero if tracing is enabled. The return value is
+ *          passed to ZSTD_trace_compress_end().
+ */
+ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_compress_begin(
+    struct ZSTD_CCtx_s const* cctx);
+
+/**
+ * Trace the end of a compression call.
+ * @param ctx The return value of ZSTD_trace_compress_begin().
+ * @param trace The zstd tracing info.
+ */
+ZSTD_WEAK_ATTR void ZSTD_trace_compress_end(
+    ZSTD_TraceCtx ctx,
+    ZSTD_Trace const* trace);
+
+/**
+ * Trace the beginning of a decompression call.
+ * @param dctx The dctx pointer for the decompression.
+ *             It can be used as a key to map begin() to end().
+ * @returns Non-zero if tracing is enabled. The return value is
+ *          passed to ZSTD_trace_compress_end().
+ */
+ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_decompress_begin(
+    struct ZSTD_DCtx_s const* dctx);
+
+/**
+ * Trace the end of a decompression call.
+ * @param ctx The return value of ZSTD_trace_decompress_begin().
+ * @param trace The zstd tracing info.
+ */
+ZSTD_WEAK_ATTR void ZSTD_trace_decompress_end(
+    ZSTD_TraceCtx ctx,
+    ZSTD_Trace const* trace);
+
+#endif /* ZSTD_TRACE */
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* ZSTD_TRACE_H */
index a427598..b4297ec 100644 (file)
@@ -1,6 +1,6 @@
 /* ******************************************************************
  * FSE : Finite State Entropy encoder
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  *  You can contact the author at :
  *  - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -15,8 +15,6 @@
 /* **************************************************************
 *  Includes
 ****************************************************************/
-#include <stdlib.h>     /* malloc, free, qsort */
-#include <string.h>     /* memcpy, memset */
 #include "../common/compiler.h"
 #include "../common/mem.h"        /* U32, U16, etc. */
 #include "../common/debug.h"      /* assert, DEBUGLOG */
@@ -25,6 +23,9 @@
 #define FSE_STATIC_LINKING_ONLY
 #include "../common/fse.h"
 #include "../common/error_private.h"
+#define ZSTD_DEPS_NEED_MALLOC
+#define ZSTD_DEPS_NEED_MATH64
+#include "../common/zstd_deps.h"  /* ZSTD_malloc, ZSTD_free, ZSTD_memcpy, ZSTD_memset */
 
 
 /* **************************************************************
@@ -74,13 +75,15 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct,
     void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ;
     FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
     U32 const step = FSE_TABLESTEP(tableSize);
-    U32 cumul[FSE_MAX_SYMBOL_VALUE+2];
 
-    FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace;
+    U32* cumul = (U32*)workSpace;
+    FSE_FUNCTION_TYPE* tableSymbol = (FSE_FUNCTION_TYPE*)(cumul + (maxSymbolValue + 2));
+
     U32 highThreshold = tableSize-1;
 
+    if ((size_t)workSpace & 3) return ERROR(GENERIC); /* Must be 4 byte aligned */
+    if (FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) > wkspSize) return ERROR(tableLog_tooLarge);
     /* CTable header */
-    if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge);
     tableU16[-2] = (U16) tableLog;
     tableU16[-1] = (U16) maxSymbolValue;
     assert(tableLog < 16);   /* required for threshold strategy to work */
@@ -89,7 +92,7 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct,
      * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
 
      #ifdef __clang_analyzer__
-     memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize);   /* useless initialization, just to keep scan-build happy */
+     ZSTD_memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize);   /* useless initialization, just to keep scan-build happy */
      #endif
 
     /* symbol start positions */
@@ -168,12 +171,13 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct,
     return 0;
 }
 
-
+#ifndef ZSTD_NO_UNUSED_FUNCTIONS
 size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
 {
     FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE];   /* memset() is not necessary, even if static analyzer complain about it */
     return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol));
 }
+#endif
 
 
 
@@ -307,10 +311,10 @@ FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog)
     size_t size;
     if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
     size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);
-    return (FSE_CTable*)malloc(size);
+    return (FSE_CTable*)ZSTD_malloc(size);
 }
 
-void FSE_freeCTable (FSE_CTable* ct) { free(ct); }
+void FSE_freeCTable (FSE_CTable* ct) { ZSTD_free(ct); }
 
 /* provides the minimum logSize to safely represent a distribution */
 static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
@@ -341,11 +345,10 @@ unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxS
     return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2);
 }
 
-
 /* Secondary normalization method.
    To be used when primary method fails. */
 
-static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue)
+static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue, short lowProbCount)
 {
     short const NOT_YET_ASSIGNED = -2;
     U32 s;
@@ -362,7 +365,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count,
             continue;
         }
         if (count[s] <= lowThreshold) {
-            norm[s] = -1;
+            norm[s] = lowProbCount;
             distributed++;
             total -= count[s];
             continue;
@@ -414,7 +417,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count,
 
     {   U64 const vStepLog = 62 - tableLog;
         U64 const mid = (1ULL << (vStepLog-1)) - 1;
-        U64 const rStep = ((((U64)1<<vStepLog) * ToDistribute) + mid) / total;   /* scale on remaining */
+        U64 const rStep = ZSTD_div64((((U64)1<<vStepLog) * ToDistribute) + mid, (U32)total);   /* scale on remaining */
         U64 tmpTotal = mid;
         for (s=0; s<=maxSymbolValue; s++) {
             if (norm[s]==NOT_YET_ASSIGNED) {
@@ -431,10 +434,9 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count,
     return 0;
 }
 
-
 size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
                            const unsigned* count, size_t total,
-                           unsigned maxSymbolValue)
+                           unsigned maxSymbolValue, unsigned useLowProbCount)
 {
     /* Sanity checks */
     if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
@@ -443,8 +445,9 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
     if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC);   /* Too small tableLog, compression potentially impossible */
 
     {   static U32 const rtbTable[] = {     0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 };
+        short const lowProbCount = useLowProbCount ? -1 : 1;
         U64 const scale = 62 - tableLog;
-        U64 const step = ((U64)1<<62) / total;   /* <== here, one division ! */
+        U64 const step = ZSTD_div64((U64)1<<62, (U32)total);   /* <== here, one division ! */
         U64 const vStep = 1ULL<<(scale-20);
         int stillToDistribute = 1<<tableLog;
         unsigned s;
@@ -456,7 +459,7 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
             if (count[s] == total) return 0;   /* rle special case */
             if (count[s] == 0) { normalizedCounter[s]=0; continue; }
             if (count[s] <= lowThreshold) {
-                normalizedCounter[s] = -1;
+                normalizedCounter[s] = lowProbCount;
                 stillToDistribute--;
             } else {
                 short proba = (short)((count[s]*step) >> scale);
@@ -470,7 +473,7 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
         }   }
         if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) {
             /* corner case, need another normalization method */
-            size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);
+            size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue, lowProbCount);
             if (FSE_isError(errorCode)) return errorCode;
         }
         else normalizedCounter[largest] += (short)stillToDistribute;
@@ -625,6 +628,7 @@ size_t FSE_compress_usingCTable (void* dst, size_t dstSize,
 
 size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
 
+#ifndef ZSTD_NO_UNUSED_FUNCTIONS
 /* FSE_compress_wksp() :
  * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
  * `wkspSize` size must be `(1<<tableLog)`.
@@ -643,7 +647,7 @@ size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t src
     size_t const scratchBufferSize = wkspSize - (CTableSize * sizeof(FSE_CTable));
 
     /* init conditions */
-    if (wkspSize < FSE_WKSP_SIZE_U32(tableLog, maxSymbolValue)) return ERROR(tableLog_tooLarge);
+    if (wkspSize < FSE_COMPRESS_WKSP_SIZE_U32(tableLog, maxSymbolValue)) return ERROR(tableLog_tooLarge);
     if (srcSize <= 1) return 0;  /* Not compressible */
     if (!maxSymbolValue) maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
     if (!tableLog) tableLog = FSE_DEFAULT_TABLELOG;
@@ -656,7 +660,7 @@ size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t src
     }
 
     tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue);
-    CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) );
+    CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue, /* useLowProbCount */ srcSize >= 2048) );
 
     /* Write table description header */
     {   CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
@@ -678,13 +682,16 @@ size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t src
 
 typedef struct {
     FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)];
-    BYTE scratchBuffer[1 << FSE_MAX_TABLELOG];
+    union {
+      U32 hist_wksp[HIST_WKSP_SIZE_U32];
+      BYTE scratchBuffer[1 << FSE_MAX_TABLELOG];
+    } workspace;
 } fseWkspMax_t;
 
 size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog)
 {
     fseWkspMax_t scratchBuffer;
-    DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE));   /* compilation failures here means scratchBuffer is not large enough */
+    DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_COMPRESS_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE));   /* compilation failures here means scratchBuffer is not large enough */
     if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
     return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer));
 }
@@ -693,6 +700,6 @@ size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcS
 {
     return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG);
 }
-
+#endif
 
 #endif   /* FSE_COMMONDEFS_ONLY */
index 61e08c7..073c57e 100644 (file)
@@ -1,7 +1,7 @@
 /* ******************************************************************
  * hist : Histogram functions
  * part of Finite State Entropy project
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  *  You can contact the author at :
  *  - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -34,7 +34,7 @@ unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
     unsigned maxSymbolValue = *maxSymbolValuePtr;
     unsigned largestCount=0;
 
-    memset(count, 0, (maxSymbolValue+1) * sizeof(*count));
+    ZSTD_memset(count, 0, (maxSymbolValue+1) * sizeof(*count));
     if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; }
 
     while (ip<end) {
@@ -60,9 +60,9 @@ typedef enum { trustInput, checkMaxSymbolValue } HIST_checkInput_e;
  * this design makes better use of OoO cpus,
  * and is noticeably faster when some values are heavily repeated.
  * But it needs some additional workspace for intermediate tables.
- * `workSpace` size must be a table of size >= HIST_WKSP_SIZE_U32.
+ * `workSpace` must be a U32 table of size >= HIST_WKSP_SIZE_U32.
  * @return : largest histogram frequency,
- *           or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */
+ *           or an error code (notably when histogram's alphabet is larger than *maxSymbolValuePtr) */
 static size_t HIST_count_parallel_wksp(
                                 unsigned* count, unsigned* maxSymbolValuePtr,
                                 const void* source, size_t sourceSize,
@@ -71,22 +71,21 @@ static size_t HIST_count_parallel_wksp(
 {
     const BYTE* ip = (const BYTE*)source;
     const BYTE* const iend = ip+sourceSize;
-    unsigned maxSymbolValue = *maxSymbolValuePtr;
+    size_t const countSize = (*maxSymbolValuePtr + 1) * sizeof(*count);
     unsigned max=0;
     U32* const Counting1 = workSpace;
     U32* const Counting2 = Counting1 + 256;
     U32* const Counting3 = Counting2 + 256;
     U32* const Counting4 = Counting3 + 256;
 
-    memset(workSpace, 0, 4*256*sizeof(unsigned));
-
     /* safety checks */
+    assert(*maxSymbolValuePtr <= 255);
     if (!sourceSize) {
-        memset(count, 0, maxSymbolValue + 1);
+        ZSTD_memset(count, 0, countSize);
         *maxSymbolValuePtr = 0;
         return 0;
     }
-    if (!maxSymbolValue) maxSymbolValue = 255;            /* 0 == default */
+    ZSTD_memset(workSpace, 0, 4*256*sizeof(unsigned));
 
     /* by stripes of 16 bytes */
     {   U32 cached = MEM_read32(ip); ip += 4;
@@ -118,21 +117,18 @@ static size_t HIST_count_parallel_wksp(
     /* finish last symbols */
     while (ip<iend) Counting1[*ip++]++;
 
-    if (check) {   /* verify stats will fit into destination table */
-        U32 s; for (s=255; s>maxSymbolValue; s--) {
-            Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
-            if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall);
-    }   }
-
     {   U32 s;
-        if (maxSymbolValue > 255) maxSymbolValue = 255;
-        for (s=0; s<=maxSymbolValue; s++) {
-            count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
-            if (count[s] > max) max = count[s];
+        for (s=0; s<256; s++) {
+            Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
+            if (Counting1[s] > max) max = Counting1[s];
     }   }
 
-    while (!count[maxSymbolValue]) maxSymbolValue--;
-    *maxSymbolValuePtr = maxSymbolValue;
+    {   unsigned maxSymbolValue = 255;
+        while (!Counting1[maxSymbolValue]) maxSymbolValue--;
+        if (check && maxSymbolValue > *maxSymbolValuePtr) return ERROR(maxSymbolValue_tooSmall);
+        *maxSymbolValuePtr = maxSymbolValue;
+        ZSTD_memmove(count, Counting1, countSize);   /* in case count & Counting1 are overlapping */
+    }
     return (size_t)max;
 }
 
@@ -152,14 +148,6 @@ size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
     return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, trustInput, (U32*)workSpace);
 }
 
-/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */
-size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
-                     const void* source, size_t sourceSize)
-{
-    unsigned tmpCounters[HIST_WKSP_SIZE_U32];
-    return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters));
-}
-
 /* HIST_count_wksp() :
  * Same as HIST_count(), but using an externally provided scratch buffer.
  * `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */
@@ -175,9 +163,19 @@ size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
     return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace, workSpaceSize);
 }
 
+#ifndef ZSTD_NO_UNUSED_FUNCTIONS
+/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */
+size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
+                     const void* source, size_t sourceSize)
+{
+    unsigned tmpCounters[HIST_WKSP_SIZE_U32];
+    return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters));
+}
+
 size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr,
                  const void* src, size_t srcSize)
 {
     unsigned tmpCounters[HIST_WKSP_SIZE_U32];
     return HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters, sizeof(tmpCounters));
 }
+#endif
index 77e3ec4..228ed48 100644 (file)
@@ -1,7 +1,7 @@
 /* ******************************************************************
  * hist : Histogram functions
  * part of Finite State Entropy project
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  *  You can contact the author at :
  *  - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -14,7 +14,7 @@
 ****************************************************************** */
 
 /* --- dependencies --- */
-#include <stddef.h>   /* size_t */
+#include "../common/zstd_deps.h"   /* size_t */
 
 
 /* --- simple histogram functions --- */
index 5468798..485906e 100644 (file)
@@ -1,6 +1,6 @@
 /* ******************************************************************
  * Huffman encoder, part of New Generation Entropy library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  *  You can contact the author at :
  *  - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -23,8 +23,7 @@
 /* **************************************************************
 *  Includes
 ****************************************************************/
-#include <string.h>     /* memcpy, memset */
-#include <stdio.h>      /* printf (debug) */
+#include "../common/zstd_deps.h"     /* ZSTD_memcpy, ZSTD_memset */
 #include "../common/compiler.h"
 #include "../common/bitstream.h"
 #include "hist.h"
@@ -60,7 +59,15 @@ unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxS
  * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
  */
 #define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
-static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize)
+
+typedef struct {
+    FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
+    U32 scratchBuffer[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(HUF_TABLELOG_MAX, MAX_FSE_TABLELOG_FOR_HUFF_HEADER)];
+    unsigned count[HUF_TABLELOG_MAX+1];
+    S16 norm[HUF_TABLELOG_MAX+1];
+} HUF_CompressWeightsWksp;
+
+static size_t HUF_compressWeights(void* dst, size_t dstSize, const void* weightTable, size_t wtSize, void* workspace, size_t workspaceSize)
 {
     BYTE* const ostart = (BYTE*) dst;
     BYTE* op = ostart;
@@ -68,33 +75,30 @@ static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weight
 
     unsigned maxSymbolValue = HUF_TABLELOG_MAX;
     U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
+    HUF_CompressWeightsWksp* wksp = (HUF_CompressWeightsWksp*)workspace;
 
-    FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
-    BYTE scratchBuffer[1<<MAX_FSE_TABLELOG_FOR_HUFF_HEADER];
-
-    unsigned count[HUF_TABLELOG_MAX+1];
-    S16 norm[HUF_TABLELOG_MAX+1];
+    if (workspaceSize < sizeof(HUF_CompressWeightsWksp)) return ERROR(GENERIC);
 
     /* init conditions */
     if (wtSize <= 1) return 0;  /* Not compressible */
 
     /* Scan input and build symbol stats */
-    {   unsigned const maxCount = HIST_count_simple(count, &maxSymbolValue, weightTable, wtSize);   /* never fails */
+    {   unsigned const maxCount = HIST_count_simple(wksp->count, &maxSymbolValue, weightTable, wtSize);   /* never fails */
         if (maxCount == wtSize) return 1;   /* only a single symbol in src : rle */
         if (maxCount == 1) return 0;        /* each symbol present maximum once => not compressible */
     }
 
     tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
-    CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) );
+    CHECK_F( FSE_normalizeCount(wksp->norm, tableLog, wksp->count, wtSize, maxSymbolValue, /* useLowProbCount */ 0) );
 
     /* Write table description header */
-    {   CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), norm, maxSymbolValue, tableLog) );
+    {   CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), wksp->norm, maxSymbolValue, tableLog) );
         op += hSize;
     }
 
     /* Compress */
-    CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) );
-    {   CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, CTable) );
+    CHECK_F( FSE_buildCTable_wksp(wksp->CTable, wksp->norm, maxSymbolValue, tableLog, wksp->scratchBuffer, sizeof(wksp->scratchBuffer)) );
+    {   CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, wksp->CTable) );
         if (cSize == 0) return 0;   /* not enough space for compressed data */
         op += cSize;
     }
@@ -103,34 +107,33 @@ static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weight
 }
 
 
-struct HUF_CElt_s {
-  U16  val;
-  BYTE nbBits;
-};   /* typedef'd to HUF_CElt within "huf.h" */
-
-/*! HUF_writeCTable() :
-    `CTable` : Huffman tree to save, using huf representation.
-    @return : size of saved CTable */
-size_t HUF_writeCTable (void* dst, size_t maxDstSize,
-                        const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog)
-{
+typedef struct {
+    HUF_CompressWeightsWksp wksp;
     BYTE bitsToWeight[HUF_TABLELOG_MAX + 1];   /* precomputed conversion table */
     BYTE huffWeight[HUF_SYMBOLVALUE_MAX];
+} HUF_WriteCTableWksp;
+
+size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize,
+                            const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog,
+                            void* workspace, size_t workspaceSize)
+{
     BYTE* op = (BYTE*)dst;
     U32 n;
+    HUF_WriteCTableWksp* wksp = (HUF_WriteCTableWksp*)workspace;
 
-     /* check conditions */
+    /* check conditions */
+    if (workspaceSize < sizeof(HUF_WriteCTableWksp)) return ERROR(GENERIC);
     if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
 
     /* convert to weight */
-    bitsToWeight[0] = 0;
+    wksp->bitsToWeight[0] = 0;
     for (n=1; n<huffLog+1; n++)
-        bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
+        wksp->bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
     for (n=0; n<maxSymbolValue; n++)
-        huffWeight[n] = bitsToWeight[CTable[n].nbBits];
+        wksp->huffWeight[n] = wksp->bitsToWeight[CTable[n].nbBits];
 
     /* attempt weights compression by FSE */
-    {   CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) );
+    {   CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, wksp->huffWeight, maxSymbolValue, &wksp->wksp, sizeof(wksp->wksp)) );
         if ((hSize>1) & (hSize < maxSymbolValue/2)) {   /* FSE compressed */
             op[0] = (BYTE)hSize;
             return hSize+1;
@@ -140,12 +143,22 @@ size_t HUF_writeCTable (void* dst, size_t maxDstSize,
     if (maxSymbolValue > (256-128)) return ERROR(GENERIC);   /* should not happen : likely means source cannot be compressed */
     if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall);   /* not enough space within dst buffer */
     op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1));
-    huffWeight[maxSymbolValue] = 0;   /* to be sure it doesn't cause msan issue in final combination */
+    wksp->huffWeight[maxSymbolValue] = 0;   /* to be sure it doesn't cause msan issue in final combination */
     for (n=0; n<maxSymbolValue; n+=2)
-        op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]);
+        op[(n/2)+1] = (BYTE)((wksp->huffWeight[n] << 4) + wksp->huffWeight[n+1]);
     return ((maxSymbolValue+1)/2) + 1;
 }
 
+/*! HUF_writeCTable() :
+    `CTable` : Huffman tree to save, using huf representation.
+    @return : size of saved CTable */
+size_t HUF_writeCTable (void* dst, size_t maxDstSize,
+                        const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog)
+{
+    HUF_WriteCTableWksp wksp;
+    return HUF_writeCTable_wksp(dst, maxDstSize, CTable, maxSymbolValue, huffLog, &wksp, sizeof(wksp));
+}
+
 
 size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* hasZeroWeights)
 {
@@ -156,6 +169,7 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void
 
     /* get symbol weights */
     CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize));
+    *hasZeroWeights = (rankVal[0] > 0);
 
     /* check result */
     if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
@@ -164,16 +178,14 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void
     /* Prepare base value per rank */
     {   U32 n, nextRankStart = 0;
         for (n=1; n<=tableLog; n++) {
-            U32 current = nextRankStart;
+            U32 curr = nextRankStart;
             nextRankStart += (rankVal[n] << (n-1));
-            rankVal[n] = current;
+            rankVal[n] = curr;
     }   }
 
     /* fill nbBits */
-    *hasZeroWeights = 0;
     {   U32 n; for (n=0; n<nbSymbols; n++) {
             const U32 w = huffWeight[n];
-            *hasZeroWeights |= (w == 0);
             CTable[n].nbBits = (BYTE)(tableLog + 1 - w) & -(w != 0);
     }   }
 
@@ -212,32 +224,63 @@ typedef struct nodeElt_s {
     BYTE nbBits;
 } nodeElt;
 
+/**
+ * HUF_setMaxHeight():
+ * Enforces maxNbBits on the Huffman tree described in huffNode.
+ *
+ * It sets all nodes with nbBits > maxNbBits to be maxNbBits. Then it adjusts
+ * the tree to so that it is a valid canonical Huffman tree.
+ *
+ * @pre               The sum of the ranks of each symbol == 2^largestBits,
+ *                    where largestBits == huffNode[lastNonNull].nbBits.
+ * @post              The sum of the ranks of each symbol == 2^largestBits,
+ *                    where largestBits is the return value <= maxNbBits.
+ *
+ * @param huffNode    The Huffman tree modified in place to enforce maxNbBits.
+ * @param lastNonNull The symbol with the lowest count in the Huffman tree.
+ * @param maxNbBits   The maximum allowed number of bits, which the Huffman tree
+ *                    may not respect. After this function the Huffman tree will
+ *                    respect maxNbBits.
+ * @return            The maximum number of bits of the Huffman tree after adjustment,
+ *                    necessarily no more than maxNbBits.
+ */
 static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
 {
     const U32 largestBits = huffNode[lastNonNull].nbBits;
-    if (largestBits <= maxNbBits) return largestBits;   /* early exit : no elt > maxNbBits */
+    /* early exit : no elt > maxNbBits, so the tree is already valid. */
+    if (largestBits <= maxNbBits) return largestBits;
 
     /* there are several too large elements (at least >= 2) */
     {   int totalCost = 0;
         const U32 baseCost = 1 << (largestBits - maxNbBits);
         int n = (int)lastNonNull;
 
+        /* Adjust any ranks > maxNbBits to maxNbBits.
+         * Compute totalCost, which is how far the sum of the ranks is
+         * we are over 2^largestBits after adjust the offending ranks.
+         */
         while (huffNode[n].nbBits > maxNbBits) {
             totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits));
             huffNode[n].nbBits = (BYTE)maxNbBits;
-            n --;
-        }  /* n stops at huffNode[n].nbBits <= maxNbBits */
-        while (huffNode[n].nbBits == maxNbBits) n--;   /* n end at index of smallest symbol using < maxNbBits */
+            n--;
+        }
+        /* n stops at huffNode[n].nbBits <= maxNbBits */
+        assert(huffNode[n].nbBits <= maxNbBits);
+        /* n end at index of smallest symbol using < maxNbBits */
+        while (huffNode[n].nbBits == maxNbBits) --n;
 
-        /* renorm totalCost */
-        totalCost >>= (largestBits - maxNbBits);  /* note : totalCost is necessarily a multiple of baseCost */
+        /* renorm totalCost from 2^largestBits to 2^maxNbBits
+         * note : totalCost is necessarily a multiple of baseCost */
+        assert((totalCost & (baseCost - 1)) == 0);
+        totalCost >>= (largestBits - maxNbBits);
+        assert(totalCost > 0);
 
         /* repay normalized cost */
         {   U32 const noSymbol = 0xF0F0F0F0;
             U32 rankLast[HUF_TABLELOG_MAX+2];
 
-            /* Get pos of last (smallest) symbol per rank */
-            memset(rankLast, 0xF0, sizeof(rankLast));
+            /* Get pos of last (smallest = lowest cum. count) symbol per rank */
+            ZSTD_memset(rankLast, 0xF0, sizeof(rankLast));
             {   U32 currentNbBits = maxNbBits;
                 int pos;
                 for (pos=n ; pos >= 0; pos--) {
@@ -247,34 +290,65 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
             }   }
 
             while (totalCost > 0) {
+                /* Try to reduce the next power of 2 above totalCost because we
+                 * gain back half the rank.
+                 */
                 U32 nBitsToDecrease = BIT_highbit32((U32)totalCost) + 1;
                 for ( ; nBitsToDecrease > 1; nBitsToDecrease--) {
                     U32 const highPos = rankLast[nBitsToDecrease];
                     U32 const lowPos = rankLast[nBitsToDecrease-1];
                     if (highPos == noSymbol) continue;
+                    /* Decrease highPos if no symbols of lowPos or if it is
+                     * not cheaper to remove 2 lowPos than highPos.
+                     */
                     if (lowPos == noSymbol) break;
                     {   U32 const highTotal = huffNode[highPos].count;
                         U32 const lowTotal = 2 * huffNode[lowPos].count;
                         if (highTotal <= lowTotal) break;
                 }   }
                 /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */
+                assert(rankLast[nBitsToDecrease] != noSymbol || nBitsToDecrease == 1);
                 /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */
                 while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol))
-                    nBitsToDecrease ++;
+                    nBitsToDecrease++;
+                assert(rankLast[nBitsToDecrease] != noSymbol);
+                /* Increase the number of bits to gain back half the rank cost. */
                 totalCost -= 1 << (nBitsToDecrease-1);
+                huffNode[rankLast[nBitsToDecrease]].nbBits++;
+
+                /* Fix up the new rank.
+                 * If the new rank was empty, this symbol is now its smallest.
+                 * Otherwise, this symbol will be the largest in the new rank so no adjustment.
+                 */
                 if (rankLast[nBitsToDecrease-1] == noSymbol)
-                    rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease];   /* this rank is no longer empty */
-                huffNode[rankLast[nBitsToDecrease]].nbBits ++;
+                    rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease];
+                /* Fix up the old rank.
+                 * If the symbol was at position 0, meaning it was the highest weight symbol in the tree,
+                 * it must be the only symbol in its rank, so the old rank now has no symbols.
+                 * Otherwise, since the Huffman nodes are sorted by count, the previous position is now
+                 * the smallest node in the rank. If the previous position belongs to a different rank,
+                 * then the rank is now empty.
+                 */
                 if (rankLast[nBitsToDecrease] == 0)    /* special case, reached largest symbol */
                     rankLast[nBitsToDecrease] = noSymbol;
                 else {
                     rankLast[nBitsToDecrease]--;
                     if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease)
                         rankLast[nBitsToDecrease] = noSymbol;   /* this rank is now empty */
-            }   }   /* while (totalCost > 0) */
-
+                }
+            }   /* while (totalCost > 0) */
+
+            /* If we've removed too much weight, then we have to add it back.
+             * To avoid overshooting again, we only adjust the smallest rank.
+             * We take the largest nodes from the lowest rank 0 and move them
+             * to rank 1. There's guaranteed to be enough rank 0 symbols because
+             * TODO.
+             */
             while (totalCost < 0) {  /* Sometimes, cost correction overshoot */
-                if (rankLast[1] == noSymbol) {  /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
+                /* special case : no rank 1 symbol (using maxNbBits-1);
+                 * let's create one from largest rank 0 (using maxNbBits).
+                 */
+                if (rankLast[1] == noSymbol) {
                     while (huffNode[n].nbBits == maxNbBits) n--;
                     huffNode[n+1].nbBits--;
                     assert(n >= 0);
@@ -285,14 +359,16 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
                 huffNode[ rankLast[1] + 1 ].nbBits--;
                 rankLast[1]++;
                 totalCost ++;
-    }   }   }   /* there are several too large elements (at least >= 2) */
+            }
+        }   /* repay normalized cost */
+    }   /* there are several too large elements (at least >= 2) */
 
     return maxNbBits;
 }
 
 typedef struct {
     U32 base;
-    U32 current;
+    U32 curr;
 } rankPos;
 
 typedef nodeElt huffNodeTable[HUF_CTABLE_WORKSPACE_SIZE_U32];
@@ -304,21 +380,45 @@ typedef struct {
   rankPos rankPosition[RANK_POSITION_TABLE_SIZE];
 } HUF_buildCTable_wksp_tables;
 
+/**
+ * HUF_sort():
+ * Sorts the symbols [0, maxSymbolValue] by count[symbol] in decreasing order.
+ *
+ * @param[out] huffNode       Sorted symbols by decreasing count. Only members `.count` and `.byte` are filled.
+ *                            Must have (maxSymbolValue + 1) entries.
+ * @param[in]  count          Histogram of the symbols.
+ * @param[in]  maxSymbolValue Maximum symbol value.
+ * @param      rankPosition   This is a scratch workspace. Must have RANK_POSITION_TABLE_SIZE entries.
+ */
 static void HUF_sort(nodeElt* huffNode, const unsigned* count, U32 maxSymbolValue, rankPos* rankPosition)
 {
-    U32 n;
-
-    memset(rankPosition, 0, sizeof(*rankPosition) * RANK_POSITION_TABLE_SIZE);
-    for (n=0; n<=maxSymbolValue; n++) {
-        U32 r = BIT_highbit32(count[n] + 1);
-        rankPosition[r].base ++;
+    int n;
+    int const maxSymbolValue1 = (int)maxSymbolValue + 1;
+
+    /* Compute base and set curr to base.
+     * For symbol s let lowerRank = BIT_highbit32(count[n]+1) and rank = lowerRank + 1.
+     * Then 2^lowerRank <= count[n]+1 <= 2^rank.
+     * We attribute each symbol to lowerRank's base value, because we want to know where
+     * each rank begins in the output, so for rank R we want to count ranks R+1 and above.
+     */
+    ZSTD_memset(rankPosition, 0, sizeof(*rankPosition) * RANK_POSITION_TABLE_SIZE);
+    for (n = 0; n < maxSymbolValue1; ++n) {
+        U32 lowerRank = BIT_highbit32(count[n] + 1);
+        rankPosition[lowerRank].base++;
     }
-    for (n=30; n>0; n--) rankPosition[n-1].base += rankPosition[n].base;
-    for (n=0; n<32; n++) rankPosition[n].current = rankPosition[n].base;
-    for (n=0; n<=maxSymbolValue; n++) {
+    assert(rankPosition[RANK_POSITION_TABLE_SIZE - 1].base == 0);
+    for (n = RANK_POSITION_TABLE_SIZE - 1; n > 0; --n) {
+        rankPosition[n-1].base += rankPosition[n].base;
+        rankPosition[n-1].curr = rankPosition[n-1].base;
+    }
+    /* Sort */
+    for (n = 0; n < maxSymbolValue1; ++n) {
         U32 const c = count[n];
         U32 const r = BIT_highbit32(c+1) + 1;
-        U32 pos = rankPosition[r].current++;
+        U32 pos = rankPosition[r].curr++;
+        /* Insert into the correct position in the rank.
+         * We have at most 256 symbols, so this insertion should be fine.
+         */
         while ((pos > rankPosition[r].base) && (c > huffNode[pos-1].count)) {
             huffNode[pos] = huffNode[pos-1];
             pos--;
@@ -335,28 +435,20 @@ static void HUF_sort(nodeElt* huffNode, const unsigned* count, U32 maxSymbolValu
  */
 #define STARTNODE (HUF_SYMBOLVALUE_MAX+1)
 
-size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize)
+/* HUF_buildTree():
+ * Takes the huffNode array sorted by HUF_sort() and builds an unlimited-depth Huffman tree.
+ *
+ * @param huffNode        The array sorted by HUF_sort(). Builds the Huffman tree in this array.
+ * @param maxSymbolValue  The maximum symbol value.
+ * @return                The smallest node in the Huffman tree (by count).
+ */
+static int HUF_buildTree(nodeElt* huffNode, U32 maxSymbolValue)
 {
-    HUF_buildCTable_wksp_tables* const wksp_tables = (HUF_buildCTable_wksp_tables*)workSpace;
-    nodeElt* const huffNode0 = wksp_tables->huffNodeTbl;
-    nodeElt* const huffNode = huffNode0+1;
+    nodeElt* const huffNode0 = huffNode - 1;
     int nonNullRank;
     int lowS, lowN;
     int nodeNb = STARTNODE;
     int n, nodeRoot;
-
-    /* safety checks */
-    if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC);  /* must be aligned on 4-bytes boundaries */
-    if (wkspSize < sizeof(HUF_buildCTable_wksp_tables))
-      return ERROR(workSpace_tooSmall);
-    if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT;
-    if (maxSymbolValue > HUF_SYMBOLVALUE_MAX)
-      return ERROR(maxSymbolValue_tooLarge);
-    memset(huffNode0, 0, sizeof(huffNodeTable));
-
-    /* sort, decreasing order */
-    HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition);
-
     /* init for parents */
     nonNullRank = (int)maxSymbolValue;
     while(huffNode[nonNullRank].count == 0) nonNullRank--;
@@ -383,42 +475,72 @@ size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbo
     for (n=0; n<=nonNullRank; n++)
         huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
 
+    return nonNullRank;
+}
+
+/**
+ * HUF_buildCTableFromTree():
+ * Build the CTable given the Huffman tree in huffNode.
+ *
+ * @param[out] CTable         The output Huffman CTable.
+ * @param      huffNode       The Huffman tree.
+ * @param      nonNullRank    The last and smallest node in the Huffman tree.
+ * @param      maxSymbolValue The maximum symbol value.
+ * @param      maxNbBits      The exact maximum number of bits used in the Huffman tree.
+ */
+static void HUF_buildCTableFromTree(HUF_CElt* CTable, nodeElt const* huffNode, int nonNullRank, U32 maxSymbolValue, U32 maxNbBits)
+{
+    /* fill result into ctable (val, nbBits) */
+    int n;
+    U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0};
+    U16 valPerRank[HUF_TABLELOG_MAX+1] = {0};
+    int const alphabetSize = (int)(maxSymbolValue + 1);
+    for (n=0; n<=nonNullRank; n++)
+        nbPerRank[huffNode[n].nbBits]++;
+    /* determine starting value per rank */
+    {   U16 min = 0;
+        for (n=(int)maxNbBits; n>0; n--) {
+            valPerRank[n] = min;      /* get starting value within each rank */
+            min += nbPerRank[n];
+            min >>= 1;
+    }   }
+    for (n=0; n<alphabetSize; n++)
+        CTable[huffNode[n].byte].nbBits = huffNode[n].nbBits;   /* push nbBits per symbol, symbol order */
+    for (n=0; n<alphabetSize; n++)
+        CTable[n].val = valPerRank[CTable[n].nbBits]++;   /* assign value within rank, symbol order */
+}
+
+size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize)
+{
+    HUF_buildCTable_wksp_tables* const wksp_tables = (HUF_buildCTable_wksp_tables*)workSpace;
+    nodeElt* const huffNode0 = wksp_tables->huffNodeTbl;
+    nodeElt* const huffNode = huffNode0+1;
+    int nonNullRank;
+
+    /* safety checks */
+    if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC);  /* must be aligned on 4-bytes boundaries */
+    if (wkspSize < sizeof(HUF_buildCTable_wksp_tables))
+      return ERROR(workSpace_tooSmall);
+    if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT;
+    if (maxSymbolValue > HUF_SYMBOLVALUE_MAX)
+      return ERROR(maxSymbolValue_tooLarge);
+    ZSTD_memset(huffNode0, 0, sizeof(huffNodeTable));
+
+    /* sort, decreasing order */
+    HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition);
+
+    /* build tree */
+    nonNullRank = HUF_buildTree(huffNode, maxSymbolValue);
+
     /* enforce maxTableLog */
     maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits);
+    if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC);   /* check fit into table */
 
-    /* fill result into tree (val, nbBits) */
-    {   U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0};
-        U16 valPerRank[HUF_TABLELOG_MAX+1] = {0};
-        int const alphabetSize = (int)(maxSymbolValue + 1);
-        if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC);   /* check fit into table */
-        for (n=0; n<=nonNullRank; n++)
-            nbPerRank[huffNode[n].nbBits]++;
-        /* determine stating value per rank */
-        {   U16 min = 0;
-            for (n=(int)maxNbBits; n>0; n--) {
-                valPerRank[n] = min;      /* get starting value within each rank */
-                min += nbPerRank[n];
-                min >>= 1;
-        }   }
-        for (n=0; n<alphabetSize; n++)
-            tree[huffNode[n].byte].nbBits = huffNode[n].nbBits;   /* push nbBits per symbol, symbol order */
-        for (n=0; n<alphabetSize; n++)
-            tree[n].val = valPerRank[tree[n].nbBits]++;   /* assign value within rank, symbol order */
-    }
+    HUF_buildCTableFromTree(tree, huffNode, nonNullRank, maxSymbolValue, maxNbBits);
 
     return maxNbBits;
 }
 
-/** HUF_buildCTable() :
- * @return : maxNbBits
- *  Note : count is used before tree is written, so they can safely overlap
- */
-size_t HUF_buildCTable (HUF_CElt* tree, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits)
-{
-    HUF_buildCTable_wksp_tables workspace;
-    return HUF_buildCTable_wksp(tree, count, maxSymbolValue, maxNbBits, &workspace, sizeof(workspace));
-}
-
 size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue)
 {
     size_t nbBits = 0;
@@ -629,29 +751,33 @@ static size_t HUF_compressCTable_internal(
 typedef struct {
     unsigned count[HUF_SYMBOLVALUE_MAX + 1];
     HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1];
-    HUF_buildCTable_wksp_tables buildCTable_wksp;
+    union {
+        HUF_buildCTable_wksp_tables buildCTable_wksp;
+        HUF_WriteCTableWksp writeCTable_wksp;
+    } wksps;
 } HUF_compress_tables_t;
 
 /* HUF_compress_internal() :
- * `workSpace` must a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
+ * `workSpace_align4` must be aligned on 4-bytes boundaries,
+ * and occupies the same space as a table of HUF_WORKSPACE_SIZE_U32 unsigned */
 static size_t
 HUF_compress_internal (void* dst, size_t dstSize,
                  const void* src, size_t srcSize,
                        unsigned maxSymbolValue, unsigned huffLog,
                        HUF_nbStreams_e nbStreams,
-                       void* workSpace, size_t wkspSize,
+                       void* workSpace_align4, size_t wkspSize,
                        HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat,
                  const int bmi2)
 {
-    HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace;
+    HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace_align4;
     BYTE* const ostart = (BYTE*)dst;
     BYTE* const oend = ostart + dstSize;
     BYTE* op = ostart;
 
     HUF_STATIC_ASSERT(sizeof(*table) <= HUF_WORKSPACE_SIZE);
+    assert(((size_t)workSpace_align4 & 3) == 0);   /* must be aligned on 4-bytes boundaries */
 
     /* checks & inits */
-    if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC);  /* must be aligned on 4-bytes boundaries */
     if (wkspSize < HUF_WORKSPACE_SIZE) return ERROR(workSpace_tooSmall);
     if (!srcSize) return 0;  /* Uncompressed */
     if (!dstSize) return 0;  /* cannot fit anything within dst budget */
@@ -669,7 +795,7 @@ HUF_compress_internal (void* dst, size_t dstSize,
     }
 
     /* Scan input and build symbol stats */
-    {   CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace, wkspSize) );
+    {   CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace_align4, wkspSize) );
         if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; }   /* single symbol, rle */
         if (largest <= (srcSize >> 7)+4) return 0;   /* heuristic : probably not compressible enough */
     }
@@ -691,16 +817,17 @@ HUF_compress_internal (void* dst, size_t dstSize,
     huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
     {   size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count,
                                             maxSymbolValue, huffLog,
-                                            &table->buildCTable_wksp, sizeof(table->buildCTable_wksp));
+                                            &table->wksps.buildCTable_wksp, sizeof(table->wksps.buildCTable_wksp));
         CHECK_F(maxBits);
         huffLog = (U32)maxBits;
         /* Zero unused symbols in CTable, so we can check it for validity */
-        memset(table->CTable + (maxSymbolValue + 1), 0,
+        ZSTD_memset(table->CTable + (maxSymbolValue + 1), 0,
                sizeof(table->CTable) - ((maxSymbolValue + 1) * sizeof(HUF_CElt)));
     }
 
     /* Write table description header */
-    {   CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table->CTable, maxSymbolValue, huffLog) );
+    {   CHECK_V_F(hSize, HUF_writeCTable_wksp(op, dstSize, table->CTable, maxSymbolValue, huffLog,
+                                              &table->wksps.writeCTable_wksp, sizeof(table->wksps.writeCTable_wksp)) );
         /* Check if using previous huffman table is beneficial */
         if (repeat && *repeat != HUF_repeat_none) {
             size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue);
@@ -716,7 +843,7 @@ HUF_compress_internal (void* dst, size_t dstSize,
         op += hSize;
         if (repeat) { *repeat = HUF_repeat_none; }
         if (oldHufTable)
-            memcpy(oldHufTable, table->CTable, sizeof(table->CTable));  /* Save new table */
+            ZSTD_memcpy(oldHufTable, table->CTable, sizeof(table->CTable));  /* Save new table */
     }
     return HUF_compressCTable_internal(ostart, op, oend,
                                        src, srcSize,
@@ -747,14 +874,6 @@ size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
                                  repeat, preferRepeat, bmi2);
 }
 
-size_t HUF_compress1X (void* dst, size_t dstSize,
-                 const void* src, size_t srcSize,
-                 unsigned maxSymbolValue, unsigned huffLog)
-{
-    unsigned workSpace[HUF_WORKSPACE_SIZE_U32];
-    return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
-}
-
 /* HUF_compress4X_repeat():
  * compress input using 4 streams.
  * provide workspace to generate compression tables */
@@ -784,6 +903,25 @@ size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
                                  hufTable, repeat, preferRepeat, bmi2);
 }
 
+#ifndef ZSTD_NO_UNUSED_FUNCTIONS
+/** HUF_buildCTable() :
+ * @return : maxNbBits
+ *  Note : count is used before tree is written, so they can safely overlap
+ */
+size_t HUF_buildCTable (HUF_CElt* tree, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits)
+{
+    HUF_buildCTable_wksp_tables workspace;
+    return HUF_buildCTable_wksp(tree, count, maxSymbolValue, maxNbBits, &workspace, sizeof(workspace));
+}
+
+size_t HUF_compress1X (void* dst, size_t dstSize,
+                 const void* src, size_t srcSize,
+                 unsigned maxSymbolValue, unsigned huffLog)
+{
+    unsigned workSpace[HUF_WORKSPACE_SIZE_U32];
+    return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
+}
+
 size_t HUF_compress2 (void* dst, size_t dstSize,
                 const void* src, size_t srcSize,
                 unsigned maxSymbolValue, unsigned huffLog)
@@ -796,3 +934,4 @@ size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSi
 {
     return HUF_compress2(dst, maxDstSize, src, srcSize, 255, HUF_TABLELOG_DEFAULT);
 }
+#endif
index 3f963b1..b7ee298 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -11,8 +11,7 @@
 /*-*************************************
 *  Dependencies
 ***************************************/
-#include <limits.h>         /* INT_MAX */
-#include <string.h>         /* memset */
+#include "../common/zstd_deps.h"  /* INT_MAX, ZSTD_memset, ZSTD_memcpy */
 #include "../common/cpu.h"
 #include "../common/mem.h"
 #include "hist.h"           /* HIST_countFast_wksp */
 #include "zstd_ldm.h"
 #include "zstd_compress_superblock.h"
 
+/* ***************************************************************
+*  Tuning parameters
+*****************************************************************/
+/*!
+ * COMPRESS_HEAPMODE :
+ * Select how default decompression function ZSTD_compress() allocates its context,
+ * on stack (0, default), or into heap (1).
+ * Note that functions with explicit context such as ZSTD_compressCCtx() are unaffected.
+ */
+#ifndef ZSTD_COMPRESS_HEAPMODE
+#  define ZSTD_COMPRESS_HEAPMODE 0
+#endif
+
 
 /*-*************************************
 *  Helper functions
@@ -52,6 +64,7 @@ size_t ZSTD_compressBound(size_t srcSize) {
 struct ZSTD_CDict_s {
     const void* dictContent;
     size_t dictContentSize;
+    ZSTD_dictContentType_e dictContentType; /* The dictContentType the CDict was created with */
     U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
     ZSTD_cwksp workspace;
     ZSTD_matchState_t matchState;
@@ -59,6 +72,10 @@ struct ZSTD_CDict_s {
     ZSTD_customMem customMem;
     U32 dictID;
     int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */
+    ZSTD_useRowMatchFinderMode_e useRowMatchFinder; /* Indicates whether the CDict was created with params that would use
+                                                     * row-based matchfinder. Unless the cdict is reloaded, we will use
+                                                     * the same greedy/lazy matchfinder at compression time.
+                                                     */
 };  /* typedef'd to ZSTD_CDict within "zstd.h" */
 
 ZSTD_CCtx* ZSTD_createCCtx(void)
@@ -69,7 +86,7 @@ ZSTD_CCtx* ZSTD_createCCtx(void)
 static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager)
 {
     assert(cctx != NULL);
-    memset(cctx, 0, sizeof(*cctx));
+    ZSTD_memset(cctx, 0, sizeof(*cctx));
     cctx->customMem = memManager;
     cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
     {   size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters);
@@ -82,8 +99,8 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
 {
     ZSTD_STATIC_ASSERT(zcss_init==0);
     ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
-    if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
-    {   ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
+    if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
+    {   ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_customMalloc(sizeof(ZSTD_CCtx), customMem);
         if (!cctx) return NULL;
         ZSTD_initCCtx(cctx, customMem);
         return cctx;
@@ -96,20 +113,20 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
     ZSTD_CCtx* cctx;
     if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL;  /* minimum size */
     if ((size_t)workspace & 7) return NULL;  /* must be 8-aligned */
-    ZSTD_cwksp_init(&ws, workspace, workspaceSize);
+    ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc);
 
     cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx));
     if (cctx == NULL) return NULL;
 
-    memset(cctx, 0, sizeof(ZSTD_CCtx));
+    ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx));
     ZSTD_cwksp_move(&cctx->workspace, &ws);
     cctx->staticSize = workspaceSize;
 
     /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
-    if (!ZSTD_cwksp_check_available(&cctx->workspace, HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL;
+    if (!ZSTD_cwksp_check_available(&cctx->workspace, ENTROPY_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL;
     cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
     cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
-    cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, HUF_WORKSPACE_SIZE);
+    cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, ENTROPY_WORKSPACE_SIZE);
     cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
     return cctx;
 }
@@ -119,10 +136,10 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
  */
 static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx)
 {
-    ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem);
+    ZSTD_customFree(cctx->localDict.dictBuffer, cctx->customMem);
     ZSTD_freeCDict(cctx->localDict.cdict);
-    memset(&cctx->localDict, 0, sizeof(cctx->localDict));
-    memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));
+    ZSTD_memset(&cctx->localDict, 0, sizeof(cctx->localDict));
+    ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));
     cctx->cdict = NULL;
 }
 
@@ -153,7 +170,7 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
         int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx);
         ZSTD_freeCCtxContent(cctx);
         if (!cctxInWorkspace) {
-            ZSTD_free(cctx, cctx->customMem);
+            ZSTD_customFree(cctx, cctx->customMem);
         }
     }
     return 0;
@@ -189,15 +206,90 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
 /* private API call, for dictBuilder only */
 const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
 
+/* Returns true if the strategy supports using a row based matchfinder */
+static int ZSTD_rowMatchFinderSupported(const ZSTD_strategy strategy) {
+    return (strategy >= ZSTD_greedy && strategy <= ZSTD_lazy2);
+}
+
+/* Returns true if the strategy and useRowMatchFinder mode indicate that we will use the row based matchfinder
+ * for this compression.
+ */
+static int ZSTD_rowMatchFinderUsed(const ZSTD_strategy strategy, const ZSTD_useRowMatchFinderMode_e mode) {
+    assert(mode != ZSTD_urm_auto);
+    return ZSTD_rowMatchFinderSupported(strategy) && (mode == ZSTD_urm_enableRowMatchFinder);
+}
+
+/* Returns row matchfinder usage enum given an initial mode and cParams */
+static ZSTD_useRowMatchFinderMode_e ZSTD_resolveRowMatchFinderMode(ZSTD_useRowMatchFinderMode_e mode,
+                                                                   const ZSTD_compressionParameters* const cParams) {
+#if !defined(ZSTD_NO_INTRINSICS) && (defined(__SSE2__) || defined(__ARM_NEON))
+    int const kHasSIMD128 = 1;
+#else
+    int const kHasSIMD128 = 0;
+#endif
+    if (mode != ZSTD_urm_auto) return mode; /* if requested enabled, but no SIMD, we still will use row matchfinder */
+    mode = ZSTD_urm_disableRowMatchFinder;
+    if (!ZSTD_rowMatchFinderSupported(cParams->strategy)) return mode;
+    if (kHasSIMD128) {
+        if (cParams->windowLog > 14) mode = ZSTD_urm_enableRowMatchFinder;
+    } else {
+        if (cParams->windowLog > 17) mode = ZSTD_urm_enableRowMatchFinder;
+    }
+    return mode;
+}
+
+/* Returns 1 if the arguments indicate that we should allocate a chainTable, 0 otherwise */
+static int ZSTD_allocateChainTable(const ZSTD_strategy strategy,
+                                   const ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
+                                   const U32 forDDSDict) {
+    assert(useRowMatchFinder != ZSTD_urm_auto);
+    /* We always should allocate a chaintable if we are allocating a matchstate for a DDS dictionary matchstate.
+     * We do not allocate a chaintable if we are using ZSTD_fast, or are using the row-based matchfinder.
+     */
+    return forDDSDict || ((strategy != ZSTD_fast) && !ZSTD_rowMatchFinderUsed(strategy, useRowMatchFinder));
+}
+
+/* Returns 1 if compression parameters are such that we should
+ * enable long distance matching (wlog >= 27, strategy >= btopt).
+ * Returns 0 otherwise.
+ */
+static U32 ZSTD_CParams_shouldEnableLdm(const ZSTD_compressionParameters* const cParams) {
+    return cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27;
+}
+
+/* Returns 1 if compression parameters are such that we should
+ * enable blockSplitter (wlog >= 17, strategy >= btopt).
+ * Returns 0 otherwise.
+ */
+static U32 ZSTD_CParams_useBlockSplitter(const ZSTD_compressionParameters* const cParams) {
+    return cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 17;
+}
+
 static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
         ZSTD_compressionParameters cParams)
 {
     ZSTD_CCtx_params cctxParams;
-    memset(&cctxParams, 0, sizeof(cctxParams));
+    /* should not matter, as all cParams are presumed properly defined */
+    ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT);
     cctxParams.cParams = cParams;
-    cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT;  /* should not matter, as all cParams are presumed properly defined */
+
+    /* Adjust advanced params according to cParams */
+    if (ZSTD_CParams_shouldEnableLdm(&cParams)) {
+        DEBUGLOG(4, "ZSTD_makeCCtxParamsFromCParams(): Including LDM into cctx params");
+        cctxParams.ldmParams.enableLdm = 1;
+        /* LDM is enabled by default for optimal parser and window size >= 128MB */
+        ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cParams);
+        assert(cctxParams.ldmParams.hashLog >= cctxParams.ldmParams.bucketSizeLog);
+        assert(cctxParams.ldmParams.hashRateLog < 32);
+    }
+
+    if (ZSTD_CParams_useBlockSplitter(&cParams)) {
+        DEBUGLOG(4, "ZSTD_makeCCtxParamsFromCParams(): Including block splitting into cctx params");
+        cctxParams.splitBlocks = 1;
+    }
+
+    cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams);
     assert(!ZSTD_checkCParams(cParams));
-    cctxParams.fParams.contentSizeFlag = 1;
     return cctxParams;
 }
 
@@ -205,13 +297,12 @@ static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
         ZSTD_customMem customMem)
 {
     ZSTD_CCtx_params* params;
-    if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
-    params = (ZSTD_CCtx_params*)ZSTD_calloc(
+    if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
+    params = (ZSTD_CCtx_params*)ZSTD_customCalloc(
             sizeof(ZSTD_CCtx_params), customMem);
     if (!params) { return NULL; }
+    ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
     params->customMem = customMem;
-    params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
-    params->fParams.contentSizeFlag = 1;
     return params;
 }
 
@@ -223,7 +314,7 @@ ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
 size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
 {
     if (params == NULL) { return 0; }
-    ZSTD_free(params, params->customMem);
+    ZSTD_customFree(params, params->customMem);
     return 0;
 }
 
@@ -234,35 +325,54 @@ size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params)
 
 size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
     RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
-    memset(cctxParams, 0, sizeof(*cctxParams));
+    ZSTD_memset(cctxParams, 0, sizeof(*cctxParams));
     cctxParams->compressionLevel = compressionLevel;
     cctxParams->fParams.contentSizeFlag = 1;
     return 0;
 }
 
+#define ZSTD_NO_CLEVEL 0
+
+/**
+ * Initializes the cctxParams from params and compressionLevel.
+ * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL.
+ */
+static void ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, ZSTD_parameters const* params, int compressionLevel)
+{
+    assert(!ZSTD_checkCParams(params->cParams));
+    ZSTD_memset(cctxParams, 0, sizeof(*cctxParams));
+    cctxParams->cParams = params->cParams;
+    cctxParams->fParams = params->fParams;
+    /* Should not matter, as all cParams are presumed properly defined.
+     * But, set it for tracing anyway.
+     */
+    cctxParams->compressionLevel = compressionLevel;
+    cctxParams->useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams->useRowMatchFinder, &params->cParams);
+    DEBUGLOG(4, "ZSTD_CCtxParams_init_internal: useRowMatchFinder=%d", cctxParams->useRowMatchFinder);
+}
+
 size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
 {
     RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
     FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
-    memset(cctxParams, 0, sizeof(*cctxParams));
-    assert(!ZSTD_checkCParams(params.cParams));
-    cctxParams->cParams = params.cParams;
-    cctxParams->fParams = params.fParams;
-    cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT;   /* should not matter, as all cParams are presumed properly defined */
+    ZSTD_CCtxParams_init_internal(cctxParams, &params, ZSTD_NO_CLEVEL);
     return 0;
 }
 
-/* ZSTD_assignParamsToCCtxParams() :
- * params is presumed valid at this stage */
-static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
-        const ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params)
+/**
+ * Sets cctxParams' cParams and fParams from params, but otherwise leaves them alone.
+ * @param param Validated zstd parameters.
+ */
+static void ZSTD_CCtxParams_setZstdParams(
+        ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params)
 {
-    ZSTD_CCtx_params ret = *cctxParams;
     assert(!ZSTD_checkCParams(params->cParams));
-    ret.cParams = params->cParams;
-    ret.fParams = params->fParams;
-    ret.compressionLevel = ZSTD_CLEVEL_DEFAULT;   /* should not matter, as all cParams are presumed properly defined */
-    return ret;
+    cctxParams->cParams = params->cParams;
+    cctxParams->fParams = params->fParams;
+    /* Should not matter, as all cParams are presumed properly defined.
+     * But, set it for tracing anyway.
+     */
+    cctxParams->compressionLevel = ZSTD_NO_CLEVEL;
 }
 
 ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
@@ -354,6 +464,11 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
 #endif
         return bounds;
 
+    case ZSTD_c_enableDedicatedDictSearch:
+        bounds.lowerBound = 0;
+        bounds.upperBound = 1;
+        return bounds;
+
     case ZSTD_c_enableLongDistanceMatching:
         bounds.lowerBound = 0;
         bounds.upperBound = 1;
@@ -397,7 +512,7 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
         return bounds;
 
     case ZSTD_c_forceAttachDict:
-        ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy);
+        ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceLoad);
         bounds.lowerBound = ZSTD_dictDefaultAttach;
         bounds.upperBound = ZSTD_dictForceLoad;       /* note : how to ensure at compile time that this is the highest value enum ? */
         return bounds;
@@ -418,6 +533,37 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
         bounds.upperBound = ZSTD_SRCSIZEHINT_MAX;
         return bounds;
 
+    case ZSTD_c_stableInBuffer:
+    case ZSTD_c_stableOutBuffer:
+        bounds.lowerBound = (int)ZSTD_bm_buffered;
+        bounds.upperBound = (int)ZSTD_bm_stable;
+        return bounds;
+
+    case ZSTD_c_blockDelimiters:
+        bounds.lowerBound = (int)ZSTD_sf_noBlockDelimiters;
+        bounds.upperBound = (int)ZSTD_sf_explicitBlockDelimiters;
+        return bounds;
+
+    case ZSTD_c_validateSequences:
+        bounds.lowerBound = 0;
+        bounds.upperBound = 1;
+        return bounds;
+
+    case ZSTD_c_splitBlocks:
+        bounds.lowerBound = 0;
+        bounds.upperBound = 1;
+        return bounds;
+
+    case ZSTD_c_useRowMatchFinder:
+        bounds.lowerBound = (int)ZSTD_urm_auto;
+        bounds.upperBound = (int)ZSTD_urm_enableRowMatchFinder;
+        return bounds;
+
+    case ZSTD_c_deterministicRefPrefix:
+        bounds.lowerBound = 0;
+        bounds.upperBound = 1;
+        return bounds;
+
     default:
         bounds.error = ERROR(parameter_unsupported);
         return bounds;
@@ -465,6 +611,7 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
     case ZSTD_c_jobSize:
     case ZSTD_c_overlapLog:
     case ZSTD_c_rsyncable:
+    case ZSTD_c_enableDedicatedDictSearch:
     case ZSTD_c_enableLongDistanceMatching:
     case ZSTD_c_ldmHashLog:
     case ZSTD_c_ldmMinMatch:
@@ -474,6 +621,13 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
     case ZSTD_c_literalCompressionMode:
     case ZSTD_c_targetCBlockSize:
     case ZSTD_c_srcSizeHint:
+    case ZSTD_c_stableInBuffer:
+    case ZSTD_c_stableOutBuffer:
+    case ZSTD_c_blockDelimiters:
+    case ZSTD_c_validateSequences:
+    case ZSTD_c_splitBlocks:
+    case ZSTD_c_useRowMatchFinder:
+    case ZSTD_c_deterministicRefPrefix:
     default:
         return 0;
     }
@@ -515,12 +669,20 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
     case ZSTD_c_jobSize:
     case ZSTD_c_overlapLog:
     case ZSTD_c_rsyncable:
+    case ZSTD_c_enableDedicatedDictSearch:
     case ZSTD_c_enableLongDistanceMatching:
     case ZSTD_c_ldmHashLog:
     case ZSTD_c_ldmMinMatch:
     case ZSTD_c_ldmBucketSizeLog:
     case ZSTD_c_targetCBlockSize:
     case ZSTD_c_srcSizeHint:
+    case ZSTD_c_stableInBuffer:
+    case ZSTD_c_stableOutBuffer:
+    case ZSTD_c_blockDelimiters:
+    case ZSTD_c_validateSequences:
+    case ZSTD_c_splitBlocks:
+    case ZSTD_c_useRowMatchFinder:
+    case ZSTD_c_deterministicRefPrefix:
         break;
 
     default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
@@ -541,9 +703,10 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
 
     case ZSTD_c_compressionLevel : {
         FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
-        if (value) {  /* 0 : does not change current level */
+        if (value == 0)
+            CCtxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default */
+        else
             CCtxParams->compressionLevel = value;
-        }
         if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel;
         return 0;  /* return type (size_t) cannot represent negative values */
     }
@@ -667,6 +830,10 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
         return CCtxParams->rsyncable;
 #endif
 
+    case ZSTD_c_enableDedicatedDictSearch :
+        CCtxParams->enableDedicatedDictSearch = (value!=0);
+        return CCtxParams->enableDedicatedDictSearch;
+
     case ZSTD_c_enableLongDistanceMatching :
         CCtxParams->ldmParams.enableLdm = (value!=0);
         return CCtxParams->ldmParams.enableLdm;
@@ -707,17 +874,52 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
         CCtxParams->srcSizeHint = value;
         return CCtxParams->srcSizeHint;
 
+    case ZSTD_c_stableInBuffer:
+        BOUNDCHECK(ZSTD_c_stableInBuffer, value);
+        CCtxParams->inBufferMode = (ZSTD_bufferMode_e)value;
+        return CCtxParams->inBufferMode;
+
+    case ZSTD_c_stableOutBuffer:
+        BOUNDCHECK(ZSTD_c_stableOutBuffer, value);
+        CCtxParams->outBufferMode = (ZSTD_bufferMode_e)value;
+        return CCtxParams->outBufferMode;
+
+    case ZSTD_c_blockDelimiters:
+        BOUNDCHECK(ZSTD_c_blockDelimiters, value);
+        CCtxParams->blockDelimiters = (ZSTD_sequenceFormat_e)value;
+        return CCtxParams->blockDelimiters;
+
+    case ZSTD_c_validateSequences:
+        BOUNDCHECK(ZSTD_c_validateSequences, value);
+        CCtxParams->validateSequences = value;
+        return CCtxParams->validateSequences;
+
+    case ZSTD_c_splitBlocks:
+        BOUNDCHECK(ZSTD_c_splitBlocks, value);
+        CCtxParams->splitBlocks = value;
+        return CCtxParams->splitBlocks;
+
+    case ZSTD_c_useRowMatchFinder:
+        BOUNDCHECK(ZSTD_c_useRowMatchFinder, value);
+        CCtxParams->useRowMatchFinder = (ZSTD_useRowMatchFinderMode_e)value;
+        return CCtxParams->useRowMatchFinder;
+
+    case ZSTD_c_deterministicRefPrefix:
+        BOUNDCHECK(ZSTD_c_deterministicRefPrefix, value);
+        CCtxParams->deterministicRefPrefix = !!value;
+        return CCtxParams->deterministicRefPrefix;
+
     default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
     }
 }
 
-size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value)
+size_t ZSTD_CCtx_getParameter(ZSTD_CCtx const* cctx, ZSTD_cParameter param, int* value)
 {
     return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value);
 }
 
 size_t ZSTD_CCtxParams_getParameter(
-        ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value)
+        ZSTD_CCtx_params const* CCtxParams, ZSTD_cParameter param, int* value)
 {
     switch(param)
     {
@@ -794,6 +996,9 @@ size_t ZSTD_CCtxParams_getParameter(
         *value = CCtxParams->rsyncable;
         break;
 #endif
+    case ZSTD_c_enableDedicatedDictSearch :
+        *value = CCtxParams->enableDedicatedDictSearch;
+        break;
     case ZSTD_c_enableLongDistanceMatching :
         *value = CCtxParams->ldmParams.enableLdm;
         break;
@@ -815,6 +1020,27 @@ size_t ZSTD_CCtxParams_getParameter(
     case ZSTD_c_srcSizeHint :
         *value = (int)CCtxParams->srcSizeHint;
         break;
+    case ZSTD_c_stableInBuffer :
+        *value = (int)CCtxParams->inBufferMode;
+        break;
+    case ZSTD_c_stableOutBuffer :
+        *value = (int)CCtxParams->outBufferMode;
+        break;
+    case ZSTD_c_blockDelimiters :
+        *value = (int)CCtxParams->blockDelimiters;
+        break;
+    case ZSTD_c_validateSequences :
+        *value = (int)CCtxParams->validateSequences;
+        break;
+    case ZSTD_c_splitBlocks :
+        *value = (int)CCtxParams->splitBlocks;
+        break;
+    case ZSTD_c_useRowMatchFinder :
+        *value = (int)CCtxParams->useRowMatchFinder;
+        break;
+    case ZSTD_c_deterministicRefPrefix:
+        *value = (int)CCtxParams->deterministicRefPrefix;
+        break;
     default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
     }
     return 0;
@@ -850,6 +1076,14 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo
     return 0;
 }
 
+static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(
+        int const compressionLevel,
+        size_t const dictSize);
+static int ZSTD_dedicatedDictSearch_isSupported(
+        const ZSTD_compressionParameters* cParams);
+static void ZSTD_dedicatedDictSearch_revertCParams(
+        ZSTD_compressionParameters* cParams);
+
 /**
  * Initializes the local dict using the requested parameters.
  * NOTE: This does not use the pledged src size, because it may be used for more
@@ -858,8 +1092,6 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo
 static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx)
 {
     ZSTD_localDict* const dl = &cctx->localDict;
-    ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams(
-            &cctx->requestedParams, ZSTD_CONTENTSIZE_UNKNOWN, dl->dictSize);
     if (dl->dict == NULL) {
         /* No local dictionary. */
         assert(dl->dictBuffer == NULL);
@@ -876,12 +1108,12 @@ static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx)
     assert(cctx->cdict == NULL);
     assert(cctx->prefixDict.dict == NULL);
 
-    dl->cdict = ZSTD_createCDict_advanced(
+    dl->cdict = ZSTD_createCDict_advanced2(
             dl->dict,
             dl->dictSize,
             ZSTD_dlm_byRef,
             dl->dictContentType,
-            cParams,
+            &cctx->requestedParams,
             cctx->customMem);
     RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed");
     cctx->cdict = dl->cdict;
@@ -894,8 +1126,6 @@ size_t ZSTD_CCtx_loadDictionary_advanced(
 {
     RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
                     "Can't load a dictionary when ctx is not in init stage.");
-    RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
-                    "no malloc for static CCtx");
     DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize);
     ZSTD_clearAllDicts(cctx);  /* in case one already exists */
     if (dict == NULL || dictSize == 0)  /* no dictionary mode */
@@ -903,9 +1133,12 @@ size_t ZSTD_CCtx_loadDictionary_advanced(
     if (dictLoadMethod == ZSTD_dlm_byRef) {
         cctx->localDict.dict = dict;
     } else {
-        void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem);
+        void* dictBuffer;
+        RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
+                        "no malloc for static CCtx");
+        dictBuffer = ZSTD_customMalloc(dictSize, cctx->customMem);
         RETURN_ERROR_IF(!dictBuffer, memory_allocation, "NULL pointer!");
-        memcpy(dictBuffer, dict, dictSize);
+        ZSTD_memcpy(dictBuffer, dict, dictSize);
         cctx->localDict.dictBuffer = dictBuffer;
         cctx->localDict.dict = dictBuffer;
     }
@@ -938,6 +1171,14 @@ size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
     return 0;
 }
 
+size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool)
+{
+    RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
+                    "Can't ref a pool when ctx not in init stage.");
+    cctx->pool = pool;
+    return 0;
+}
+
 size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
 {
     return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent);
@@ -1022,23 +1263,83 @@ U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
     return hashLog - btScale;
 }
 
+/** ZSTD_dictAndWindowLog() :
+ * Returns an adjusted window log that is large enough to fit the source and the dictionary.
+ * The zstd format says that the entire dictionary is valid if one byte of the dictionary
+ * is within the window. So the hashLog and chainLog should be large enough to reference both
+ * the dictionary and the window. So we must use this adjusted dictAndWindowLog when downsizing
+ * the hashLog and windowLog.
+ * NOTE: srcSize must not be ZSTD_CONTENTSIZE_UNKNOWN.
+ */
+static U32 ZSTD_dictAndWindowLog(U32 windowLog, U64 srcSize, U64 dictSize)
+{
+    const U64 maxWindowSize = 1ULL << ZSTD_WINDOWLOG_MAX;
+    /* No dictionary ==> No change */
+    if (dictSize == 0) {
+        return windowLog;
+    }
+    assert(windowLog <= ZSTD_WINDOWLOG_MAX);
+    assert(srcSize != ZSTD_CONTENTSIZE_UNKNOWN); /* Handled in ZSTD_adjustCParams_internal() */
+    {
+        U64 const windowSize = 1ULL << windowLog;
+        U64 const dictAndWindowSize = dictSize + windowSize;
+        /* If the window size is already large enough to fit both the source and the dictionary
+         * then just use the window size. Otherwise adjust so that it fits the dictionary and
+         * the window.
+         */
+        if (windowSize >= dictSize + srcSize) {
+            return windowLog; /* Window size large enough already */
+        } else if (dictAndWindowSize >= maxWindowSize) {
+            return ZSTD_WINDOWLOG_MAX; /* Larger than max window log */
+        } else  {
+            return ZSTD_highbit32((U32)dictAndWindowSize - 1) + 1;
+        }
+    }
+}
+
 /** ZSTD_adjustCParams_internal() :
  *  optimize `cPar` for a specified input (`srcSize` and `dictSize`).
  *  mostly downsize to reduce memory consumption and initialization latency.
  * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known.
+ * `mode` is the mode for parameter adjustment. See docs for `ZSTD_cParamMode_e`.
  *  note : `srcSize==0` means 0!
  *  condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */
 static ZSTD_compressionParameters
 ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
                             unsigned long long srcSize,
-                            size_t dictSize)
+                            size_t dictSize,
+                            ZSTD_cParamMode_e mode)
 {
-    static const U64 minSrcSize = 513; /* (1<<9) + 1 */
-    static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
+    const U64 minSrcSize = 513; /* (1<<9) + 1 */
+    const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
     assert(ZSTD_checkCParams(cPar)==0);
 
-    if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN)
-        srcSize = minSrcSize;
+    switch (mode) {
+    case ZSTD_cpm_unknown:
+    case ZSTD_cpm_noAttachDict:
+        /* If we don't know the source size, don't make any
+         * assumptions about it. We will already have selected
+         * smaller parameters if a dictionary is in use.
+         */
+        break;
+    case ZSTD_cpm_createCDict:
+        /* Assume a small source size when creating a dictionary
+         * with an unkown source size.
+         */
+        if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN)
+            srcSize = minSrcSize;
+        break;
+    case ZSTD_cpm_attachDict:
+        /* Dictionary has its own dedicated parameters which have
+         * already been selected. We are selecting parameters
+         * for only the source.
+         */
+        dictSize = 0;
+        break;
+    default:
+        assert(0);
+        break;
+    }
 
     /* resize windowLog if input is small enough, to use less memory */
     if ( (srcSize < maxWindowResize)
@@ -1049,10 +1350,12 @@ ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
                             ZSTD_highbit32(tSize-1) + 1;
         if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
     }
-    if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1;
-    {   U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
-        if (cycleLog > cPar.windowLog)
-            cPar.chainLog -= (cycleLog - cPar.windowLog);
+    if (srcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+        U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize);
+        U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
+        if (cPar.hashLog > dictAndWindowLog+1) cPar.hashLog = dictAndWindowLog+1;
+        if (cycleLog > dictAndWindowLog)
+            cPar.chainLog -= (cycleLog - dictAndWindowLog);
     }
 
     if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
@@ -1068,38 +1371,50 @@ ZSTD_adjustCParams(ZSTD_compressionParameters cPar,
 {
     cPar = ZSTD_clampCParams(cPar);   /* resulting cPar is necessarily valid (all parameters within range) */
     if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN;
-    return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
+    return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize, ZSTD_cpm_unknown);
 }
 
-static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize);
-static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize);
+static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode);
+static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode);
+
+static void ZSTD_overrideCParams(
+              ZSTD_compressionParameters* cParams,
+        const ZSTD_compressionParameters* overrides)
+{
+    if (overrides->windowLog)    cParams->windowLog    = overrides->windowLog;
+    if (overrides->hashLog)      cParams->hashLog      = overrides->hashLog;
+    if (overrides->chainLog)     cParams->chainLog     = overrides->chainLog;
+    if (overrides->searchLog)    cParams->searchLog    = overrides->searchLog;
+    if (overrides->minMatch)     cParams->minMatch     = overrides->minMatch;
+    if (overrides->targetLength) cParams->targetLength = overrides->targetLength;
+    if (overrides->strategy)     cParams->strategy     = overrides->strategy;
+}
 
 ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
-        const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
+        const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode)
 {
     ZSTD_compressionParameters cParams;
     if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) {
       srcSizeHint = CCtxParams->srcSizeHint;
     }
-    cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize);
+    cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize, mode);
     if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
-    if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog;
-    if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog;
-    if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog;
-    if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog;
-    if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch;
-    if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength;
-    if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy;
+    ZSTD_overrideCParams(&cParams, &CCtxParams->cParams);
     assert(!ZSTD_checkCParams(cParams));
     /* srcSizeHint == 0 means 0 */
-    return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize);
+    return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize, mode);
 }
 
 static size_t
 ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
+                       const ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
+                       const U32 enableDedicatedDictSearch,
                        const U32 forCCtx)
 {
-    size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
+    /* chain table size should be 0 for fast or row-hash strategies */
+    size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, enableDedicatedDictSearch && !forCCtx)
+                                ? ((size_t)1 << cParams->chainLog)
+                                : 0;
     size_t const hSize = ((size_t)1) << cParams->hashLog;
     U32    const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
     size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
@@ -1109,71 +1424,117 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
                             + hSize * sizeof(U32)
                             + h3Size * sizeof(U32);
     size_t const optPotentialSpace =
-        ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32))
-      + ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32))
-      + ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32))
-      + ZSTD_cwksp_alloc_size((1<<Litbits) * sizeof(U32))
-      + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t))
-      + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
+        ZSTD_cwksp_aligned_alloc_size((MaxML+1) * sizeof(U32))
+      + ZSTD_cwksp_aligned_alloc_size((MaxLL+1) * sizeof(U32))
+      + ZSTD_cwksp_aligned_alloc_size((MaxOff+1) * sizeof(U32))
+      + ZSTD_cwksp_aligned_alloc_size((1<<Litbits) * sizeof(U32))
+      + ZSTD_cwksp_aligned_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t))
+      + ZSTD_cwksp_aligned_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
+    size_t const lazyAdditionalSpace = ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)
+                                            ? ZSTD_cwksp_aligned_alloc_size(hSize*sizeof(U16))
+                                            : 0;
     size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt))
                                 ? optPotentialSpace
                                 : 0;
+    size_t const slackSpace = ZSTD_cwksp_slack_space_required();
+
+    /* tables are guaranteed to be sized in multiples of 64 bytes (or 16 uint32_t) */
+    ZSTD_STATIC_ASSERT(ZSTD_HASHLOG_MIN >= 4 && ZSTD_WINDOWLOG_MIN >= 4 && ZSTD_CHAINLOG_MIN >= 4);
+    assert(useRowMatchFinder != ZSTD_urm_auto);
+
     DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
                 (U32)chainSize, (U32)hSize, (U32)h3Size);
-    return tableSpace + optSpace;
+    return tableSpace + optSpace + slackSpace + lazyAdditionalSpace;
+}
+
+static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal(
+        const ZSTD_compressionParameters* cParams,
+        const ldmParams_t* ldmParams,
+        const int isStatic,
+        const ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
+        const size_t buffInSize,
+        const size_t buffOutSize,
+        const U64 pledgedSrcSize)
+{
+    size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << cParams->windowLog), pledgedSrcSize));
+    size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
+    U32    const divider = (cParams->minMatch==3) ? 3 : 4;
+    size_t const maxNbSeq = blockSize / divider;
+    size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
+                            + ZSTD_cwksp_aligned_alloc_size(maxNbSeq * sizeof(seqDef))
+                            + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
+    size_t const entropySpace = ZSTD_cwksp_alloc_size(ENTROPY_WORKSPACE_SIZE);
+    size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
+    size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 0, /* forCCtx */ 1);
+
+    size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams);
+    size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize);
+    size_t const ldmSeqSpace = ldmParams->enableLdm ?
+        ZSTD_cwksp_aligned_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0;
+
+
+    size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize)
+                             + ZSTD_cwksp_alloc_size(buffOutSize);
+
+    size_t const cctxSpace = isStatic ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0;
+
+    size_t const neededSpace =
+        cctxSpace +
+        entropySpace +
+        blockStateSpace +
+        ldmSpace +
+        ldmSeqSpace +
+        matchStateSize +
+        tokenSpace +
+        bufferSpace;
+
+    DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
+    return neededSpace;
 }
 
 size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
 {
-    RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
-    {   ZSTD_compressionParameters const cParams =
-                ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0);
-        size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
-        U32    const divider = (cParams.minMatch==3) ? 3 : 4;
-        size_t const maxNbSeq = blockSize / divider;
-        size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
-                                + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
-                                + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
-        size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
-        size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
-        size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1);
+    ZSTD_compressionParameters const cParams =
+                ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
+    ZSTD_useRowMatchFinderMode_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder,
+                                                                                         &cParams);
 
-        size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams);
-        size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq));
-
-        /* estimateCCtxSize is for one-shot compression. So no buffers should
-         * be needed. However, we still allocate two 0-sized buffers, which can
-         * take space under ASAN. */
-        size_t const bufferSpace = ZSTD_cwksp_alloc_size(0)
-                                 + ZSTD_cwksp_alloc_size(0);
-
-        size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx));
-
-        size_t const neededSpace =
-            cctxSpace +
-            entropySpace +
-            blockStateSpace +
-            ldmSpace +
-            ldmSeqSpace +
-            matchStateSize +
-            tokenSpace +
-            bufferSpace;
-
-        DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
-        return neededSpace;
-    }
+    RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
+    /* estimateCCtxSize is for one-shot compression. So no buffers should
+     * be needed. However, we still allocate two 0-sized buffers, which can
+     * take space under ASAN. */
+    return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
+        &cParams, &params->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN);
 }
 
 size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
 {
-    ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
-    return ZSTD_estimateCCtxSize_usingCCtxParams(&params);
+    ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams);
+    if (ZSTD_rowMatchFinderSupported(cParams.strategy)) {
+        /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */
+        size_t noRowCCtxSize;
+        size_t rowCCtxSize;
+        initialParams.useRowMatchFinder = ZSTD_urm_disableRowMatchFinder;
+        noRowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams);
+        initialParams.useRowMatchFinder = ZSTD_urm_enableRowMatchFinder;
+        rowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams);
+        return MAX(noRowCCtxSize, rowCCtxSize);
+    } else {
+        return ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams);
+    }
 }
 
 static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
 {
-    ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
-    return ZSTD_estimateCCtxSize_usingCParams(cParams);
+    int tier = 0;
+    size_t largestSize = 0;
+    static const unsigned long long srcSizeTiers[4] = {16 KB, 128 KB, 256 KB, ZSTD_CONTENTSIZE_UNKNOWN};
+    for (; tier < 4; ++tier) {
+        /* Choose the set of cParams for a given level across all srcSizes that give the largest cctxSize */
+        ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeTiers[tier], 0, ZSTD_cpm_noAttachDict);
+        largestSize = MAX(ZSTD_estimateCCtxSize_usingCParams(cParams), largestSize);
+    }
+    return largestSize;
 }
 
 size_t ZSTD_estimateCCtxSize(int compressionLevel)
@@ -1181,6 +1542,7 @@ size_t ZSTD_estimateCCtxSize(int compressionLevel)
     int level;
     size_t memBudget = 0;
     for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
+        /* Ensure monotonically increasing memory usage as compression level increases */
         size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
         if (newMB > memBudget) memBudget = newMB;
     }
@@ -1191,27 +1553,42 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
 {
     RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
     {   ZSTD_compressionParameters const cParams =
-                ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0);
-        size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
+                ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
         size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
-        size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
-        size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
-        size_t const streamingSize = ZSTD_cwksp_alloc_size(inBuffSize)
-                                   + ZSTD_cwksp_alloc_size(outBuffSize);
-
-        return CCtxSize + streamingSize;
+        size_t const inBuffSize = (params->inBufferMode == ZSTD_bm_buffered)
+                ? ((size_t)1 << cParams.windowLog) + blockSize
+                : 0;
+        size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered)
+                ? ZSTD_compressBound(blockSize) + 1
+                : 0;
+        ZSTD_useRowMatchFinderMode_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, &params->cParams);
+
+        return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
+            &cParams, &params->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize,
+            ZSTD_CONTENTSIZE_UNKNOWN);
     }
 }
 
 size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
 {
-    ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
-    return ZSTD_estimateCStreamSize_usingCCtxParams(&params);
+    ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams);
+    if (ZSTD_rowMatchFinderSupported(cParams.strategy)) {
+        /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */
+        size_t noRowCCtxSize;
+        size_t rowCCtxSize;
+        initialParams.useRowMatchFinder = ZSTD_urm_disableRowMatchFinder;
+        noRowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams);
+        initialParams.useRowMatchFinder = ZSTD_urm_enableRowMatchFinder;
+        rowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams);
+        return MAX(noRowCCtxSize, rowCCtxSize);
+    } else {
+        return ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams);
+    }
 }
 
 static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
 {
-    ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
+    ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
     return ZSTD_estimateCStreamSize_usingCParams(cParams);
 }
 
@@ -1305,16 +1682,6 @@ static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
 }
 
 /**
- * Indicates whether this compression proceeds directly from user-provided
- * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or
- * whether the context needs to buffer the input/output (ZSTDb_buffered).
- */
-typedef enum {
-    ZSTDb_not_buffered,
-    ZSTDb_buffered
-} ZSTD_buffered_policy_e;
-
-/**
  * Controls, for this matchState reset, whether the tables need to be cleared /
  * prepared for the coming compression (ZSTDcrp_makeClean), or whether the
  * tables can be left unclean (ZSTDcrp_leaveDirty), because we know that a
@@ -1341,20 +1708,27 @@ typedef enum {
     ZSTD_resetTarget_CCtx
 } ZSTD_resetTarget_e;
 
+
 static size_t
 ZSTD_reset_matchState(ZSTD_matchState_t* ms,
                       ZSTD_cwksp* ws,
                 const ZSTD_compressionParameters* cParams,
+                const ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
                 const ZSTD_compResetPolicy_e crp,
                 const ZSTD_indexResetPolicy_e forceResetIndex,
                 const ZSTD_resetTarget_e forWho)
 {
-    size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
+    /* disable chain table allocation for fast or row-based strategies */
+    size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder,
+                                                     ms->dedicatedDictSearch && (forWho == ZSTD_resetTarget_CDict))
+                                ? ((size_t)1 << cParams->chainLog)
+                                : 0;
     size_t const hSize = ((size_t)1) << cParams->hashLog;
     U32    const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
     size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
 
     DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset);
+    assert(useRowMatchFinder != ZSTD_urm_auto);
     if (forceResetIndex == ZSTDirp_reset) {
         ZSTD_window_init(&ms->window);
         ZSTD_cwksp_mark_tables_dirty(ws);
@@ -1393,11 +1767,23 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms,
         ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
     }
 
+    if (ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)) {
+        {   /* Row match finder needs an additional table of hashes ("tags") */
+            size_t const tagTableSize = hSize*sizeof(U16);
+            ms->tagTable = (U16*)ZSTD_cwksp_reserve_aligned(ws, tagTableSize);
+            if (ms->tagTable) ZSTD_memset(ms->tagTable, 0, tagTableSize);
+        }
+        {   /* Switch to 32-entry rows if searchLog is 5 (or more) */
+            U32 const rowLog = cParams->searchLog < 5 ? 4 : 5;
+            assert(cParams->hashLog > rowLog);
+            ms->rowHashLog = cParams->hashLog - rowLog;
+        }
+    }
+
     ms->cParams = *cParams;
 
     RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation,
                     "failed a workspace allocation in ZSTD_reset_matchState");
-
     return 0;
 }
 
@@ -1414,75 +1800,85 @@ static int ZSTD_indexTooCloseToMax(ZSTD_window_t w)
     return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN);
 }
 
+/** ZSTD_dictTooBig():
+ * When dictionaries are larger than ZSTD_CHUNKSIZE_MAX they can't be loaded in
+ * one go generically. So we ensure that in that case we reset the tables to zero,
+ * so that we can load as much of the dictionary as possible.
+ */
+static int ZSTD_dictTooBig(size_t const loadedDictSize)
+{
+    return loadedDictSize > ZSTD_CHUNKSIZE_MAX;
+}
+
 /*! ZSTD_resetCCtx_internal() :
-    note : `params` are assumed fully validated at this stage */
+ * @param loadedDictSize The size of the dictionary to be loaded
+ * into the context, if any. If no dictionary is used, or the
+ * dictionary is being attached / copied, then pass 0.
+ * note : `params` are assumed fully validated at this stage.
+ */
 static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
-                                      ZSTD_CCtx_params params,
+                                      ZSTD_CCtx_params const* params,
                                       U64 const pledgedSrcSize,
+                                      size_t const loadedDictSize,
                                       ZSTD_compResetPolicy_e const crp,
                                       ZSTD_buffered_policy_e const zbuff)
 {
     ZSTD_cwksp* const ws = &zc->workspace;
-    DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
-                (U32)pledgedSrcSize, params.cParams.windowLog);
-    assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+    DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u, useRowMatchFinder=%d",
+                (U32)pledgedSrcSize, params->cParams.windowLog, (int)params->useRowMatchFinder);
+    assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
 
     zc->isFirstBlock = 1;
 
-    if (params.ldmParams.enableLdm) {
+    /* Set applied params early so we can modify them for LDM,
+     * and point params at the applied params.
+     */
+    zc->appliedParams = *params;
+    params = &zc->appliedParams;
+
+    assert(params->useRowMatchFinder != ZSTD_urm_auto);
+    if (params->ldmParams.enableLdm) {
         /* Adjust long distance matching parameters */
-        ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
-        assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
-        assert(params.ldmParams.hashRateLog < 32);
-        zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
+        ZSTD_ldm_adjustParameters(&zc->appliedParams.ldmParams, &params->cParams);
+        assert(params->ldmParams.hashLog >= params->ldmParams.bucketSizeLog);
+        assert(params->ldmParams.hashRateLog < 32);
     }
 
-    {   size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
+    {   size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params->cParams.windowLog), pledgedSrcSize));
         size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
-        U32    const divider = (params.cParams.minMatch==3) ? 3 : 4;
+        U32    const divider = (params->cParams.minMatch==3) ? 3 : 4;
         size_t const maxNbSeq = blockSize / divider;
-        size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
-                                + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
-                                + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
-        size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
-        size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
-        size_t const matchStateSize = ZSTD_sizeof_matchState(&params.cParams, /* forCCtx */ 1);
-        size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
-
-        ZSTD_indexResetPolicy_e needsIndexReset = zc->initialized ? ZSTDirp_continue : ZSTDirp_reset;
-
-        if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) {
-            needsIndexReset = ZSTDirp_reset;
-        }
+        size_t const buffOutSize = (zbuff == ZSTDb_buffered && params->outBufferMode == ZSTD_bm_buffered)
+                ? ZSTD_compressBound(blockSize) + 1
+                : 0;
+        size_t const buffInSize = (zbuff == ZSTDb_buffered && params->inBufferMode == ZSTD_bm_buffered)
+                ? windowSize + blockSize
+                : 0;
+        size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize);
+
+        int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window);
+        int const dictTooBig = ZSTD_dictTooBig(loadedDictSize);
+        ZSTD_indexResetPolicy_e needsIndexReset =
+            (indexTooClose || dictTooBig || !zc->initialized) ? ZSTDirp_reset : ZSTDirp_continue;
 
-        if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0);
+        size_t const neededSpace =
+            ZSTD_estimateCCtxSize_usingCCtxParams_internal(
+                &params->cParams, &params->ldmParams, zc->staticSize != 0, params->useRowMatchFinder,
+                buffInSize, buffOutSize, pledgedSrcSize);
+        int resizeWorkspace;
 
-        /* Check if workspace is large enough, alloc a new one if needed */
-        {   size_t const cctxSpace = zc->staticSize ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0;
-            size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
-            size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
-            size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + ZSTD_cwksp_alloc_size(buffOutSize);
-            size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams);
-            size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq));
-
-            size_t const neededSpace =
-                cctxSpace +
-                entropySpace +
-                blockStateSpace +
-                ldmSpace +
-                ldmSeqSpace +
-                matchStateSize +
-                tokenSpace +
-                bufferSpace;
+        FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!");
 
+        if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0);
+
+        {   /* Check if workspace is large enough, alloc a new one if needed */
             int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace;
             int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace);
-
-            DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers",
-                        neededSpace>>10, matchStateSize>>10, bufferSpace>>10);
+            resizeWorkspace = workspaceTooSmall || workspaceWasteful;
+            DEBUGLOG(4, "Need %zu B workspace", neededSpace);
             DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
 
-            if (workspaceTooSmall || workspaceWasteful) {
+            if (resizeWorkspace) {
                 DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB",
                             ZSTD_cwksp_sizeof(ws) >> 10,
                             neededSpace >> 10);
@@ -1503,15 +1899,14 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
                 RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock");
                 zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t));
                 RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate nextCBlock");
-                zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, HUF_WORKSPACE_SIZE);
+                zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, ENTROPY_WORKSPACE_SIZE);
                 RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace");
         }   }
 
         ZSTD_cwksp_clear(ws);
 
         /* init params */
-        zc->appliedParams = params;
-        zc->blockState.matchState.cParams = params.cParams;
+        zc->blockState.matchState.cParams = params->cParams;
         zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
         zc->consumedSrcSize = 0;
         zc->producedCSize = 0;
@@ -1524,6 +1919,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
         XXH64_reset(&zc->xxhState, 0);
         zc->stage = ZSTDcs_init;
         zc->dictID = 0;
+        zc->dictContentSize = 0;
 
         ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
 
@@ -1534,19 +1930,20 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
         zc->seqStore.maxNbLit = blockSize;
 
         /* buffers */
+        zc->bufferedPolicy = zbuff;
         zc->inBuffSize = buffInSize;
         zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize);
         zc->outBuffSize = buffOutSize;
         zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize);
 
         /* ldm bucketOffsets table */
-        if (params.ldmParams.enableLdm) {
+        if (params->ldmParams.enableLdm) {
             /* TODO: avoid memset? */
-            size_t const ldmBucketSize =
-                  ((size_t)1) << (params.ldmParams.hashLog -
-                                  params.ldmParams.bucketSizeLog);
-            zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, ldmBucketSize);
-            memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize);
+            size_t const numBuckets =
+                  ((size_t)1) << (params->ldmParams.hashLog -
+                                  params->ldmParams.bucketSizeLog);
+            zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, numBuckets);
+            ZSTD_memset(zc->ldmState.bucketOffsets, 0, numBuckets);
         }
 
         /* sequences storage */
@@ -1560,26 +1957,28 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
         FORWARD_IF_ERROR(ZSTD_reset_matchState(
             &zc->blockState.matchState,
             ws,
-            &params.cParams,
+            &params->cParams,
+            params->useRowMatchFinder,
             crp,
             needsIndexReset,
             ZSTD_resetTarget_CCtx), "");
 
         /* ldm hash table */
-        if (params.ldmParams.enableLdm) {
+        if (params->ldmParams.enableLdm) {
             /* TODO: avoid memset? */
-            size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
+            size_t const ldmHSize = ((size_t)1) << params->ldmParams.hashLog;
             zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t));
-            memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t));
+            ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t));
             zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq));
             zc->maxNbLdmSequences = maxNbLdmSeq;
 
             ZSTD_window_init(&zc->ldmState.window);
-            ZSTD_window_clear(&zc->ldmState.window);
             zc->ldmState.loadedDictEnd = 0;
         }
 
+        assert(ZSTD_cwksp_estimated_space_within_bounds(ws, neededSpace, resizeWorkspace));
         DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws));
+
         zc->initialized = 1;
 
         return 0;
@@ -1618,12 +2017,14 @@ static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict,
                                  U64 pledgedSrcSize)
 {
     size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy];
-    return ( pledgedSrcSize <= cutoff
-          || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
-          || params->attachDictPref == ZSTD_dictForceAttach )
-        && params->attachDictPref != ZSTD_dictForceCopy
-        && !params->forceWindow; /* dictMatchState isn't correctly
-                                 * handled in _enforceMaxDist */
+    int const dedicatedDictSearch = cdict->matchState.dedicatedDictSearch;
+    return dedicatedDictSearch
+        || ( ( pledgedSrcSize <= cutoff
+            || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
+            || params->attachDictPref == ZSTD_dictForceAttach )
+          && params->attachDictPref != ZSTD_dictForceCopy
+          && !params->forceWindow ); /* dictMatchState isn't correctly
+                                      * handled in _enforceMaxDist */
 }
 
 static size_t
@@ -1633,17 +2034,28 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
                         U64 pledgedSrcSize,
                         ZSTD_buffered_policy_e zbuff)
 {
-    {   const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams;
+    DEBUGLOG(4, "ZSTD_resetCCtx_byAttachingCDict() pledgedSrcSize=%llu",
+                (unsigned long long)pledgedSrcSize);
+    {
+        ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams;
         unsigned const windowLog = params.cParams.windowLog;
         assert(windowLog != 0);
         /* Resize working context table params for input only, since the dict
          * has its own tables. */
-        /* pledgeSrcSize == 0 means 0! */
-        params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0);
+        /* pledgedSrcSize == 0 means 0! */
+
+        if (cdict->matchState.dedicatedDictSearch) {
+            ZSTD_dedicatedDictSearch_revertCParams(&adjusted_cdict_cParams);
+        }
+
+        params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize,
+                                                     cdict->dictContentSize, ZSTD_cpm_attachDict);
         params.cParams.windowLog = windowLog;
-        FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+        params.useRowMatchFinder = cdict->useRowMatchFinder;    /* cdict overrides */
+        FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, &params, pledgedSrcSize,
+                                                 /* loadedDictSize */ 0,
                                                  ZSTDcrp_makeClean, zbuff), "");
-        assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
+        assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy);
     }
 
     {   const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc
@@ -1668,9 +2080,10 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
     }   }
 
     cctx->dictID = cdict->dictID;
+    cctx->dictContentSize = cdict->dictContentSize;
 
     /* copy block state */
-    memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
+    ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
 
     return 0;
 }
@@ -1683,14 +2096,18 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
 {
     const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
 
-    DEBUGLOG(4, "copying dictionary into context");
+    assert(!cdict->matchState.dedicatedDictSearch);
+    DEBUGLOG(4, "ZSTD_resetCCtx_byCopyingCDict() pledgedSrcSize=%llu",
+                (unsigned long long)pledgedSrcSize);
 
     {   unsigned const windowLog = params.cParams.windowLog;
         assert(windowLog != 0);
         /* Copy only compression parameters related to tables. */
         params.cParams = *cdict_cParams;
         params.cParams.windowLog = windowLog;
-        FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+        params.useRowMatchFinder = cdict->useRowMatchFinder;
+        FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, &params, pledgedSrcSize,
+                                                 /* loadedDictSize */ 0,
                                                  ZSTDcrp_leaveDirty, zbuff), "");
         assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
         assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog);
@@ -1698,24 +2115,37 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
     }
 
     ZSTD_cwksp_mark_tables_dirty(&cctx->workspace);
+    assert(params.useRowMatchFinder != ZSTD_urm_auto);
 
     /* copy tables */
-    {   size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
+    {   size_t const chainSize = ZSTD_allocateChainTable(cdict_cParams->strategy, cdict->useRowMatchFinder, 0 /* DDS guaranteed disabled */)
+                                                            ? ((size_t)1 << cdict_cParams->chainLog)
+                                                            : 0;
         size_t const hSize =  (size_t)1 << cdict_cParams->hashLog;
 
-        memcpy(cctx->blockState.matchState.hashTable,
+        ZSTD_memcpy(cctx->blockState.matchState.hashTable,
                cdict->matchState.hashTable,
                hSize * sizeof(U32));
-        memcpy(cctx->blockState.matchState.chainTable,
+        /* Do not copy cdict's chainTable if cctx has parameters such that it would not use chainTable */
+        if (ZSTD_allocateChainTable(cctx->appliedParams.cParams.strategy, cctx->appliedParams.useRowMatchFinder, 0 /* forDDSDict */)) {
+            ZSTD_memcpy(cctx->blockState.matchState.chainTable,
                cdict->matchState.chainTable,
                chainSize * sizeof(U32));
+        }
+        /* copy tag table */
+        if (ZSTD_rowMatchFinderUsed(cdict_cParams->strategy, cdict->useRowMatchFinder)) {
+            size_t const tagTableSize = hSize*sizeof(U16);
+            ZSTD_memcpy(cctx->blockState.matchState.tagTable,
+                cdict->matchState.tagTable,
+                tagTableSize);
+        }
     }
 
     /* Zero the hashTable3, since the cdict never fills it */
     {   int const h3log = cctx->blockState.matchState.hashLog3;
         size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
         assert(cdict->matchState.hashLog3 == 0);
-        memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
+        ZSTD_memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
     }
 
     ZSTD_cwksp_mark_tables_clean(&cctx->workspace);
@@ -1729,9 +2159,10 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
     }
 
     cctx->dictID = cdict->dictID;
+    cctx->dictContentSize = cdict->dictContentSize;
 
     /* copy block state */
-    memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
+    ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
 
     return 0;
 }
@@ -1771,16 +2202,18 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
                             U64 pledgedSrcSize,
                             ZSTD_buffered_policy_e zbuff)
 {
-    DEBUGLOG(5, "ZSTD_copyCCtx_internal");
     RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong,
                     "Can't copy a ctx that's not in init stage.");
-
-    memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
+    DEBUGLOG(5, "ZSTD_copyCCtx_internal");
+    ZSTD_memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
     {   ZSTD_CCtx_params params = dstCCtx->requestedParams;
         /* Copy only compression parameters related to tables. */
         params.cParams = srcCCtx->appliedParams.cParams;
+        assert(srcCCtx->appliedParams.useRowMatchFinder != ZSTD_urm_auto);
+        params.useRowMatchFinder = srcCCtx->appliedParams.useRowMatchFinder;
         params.fParams = fParams;
-        ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
+        ZSTD_resetCCtx_internal(dstCCtx, &params, pledgedSrcSize,
+                                /* loadedDictSize */ 0,
                                 ZSTDcrp_leaveDirty, zbuff);
         assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog);
         assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy);
@@ -1792,18 +2225,22 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
     ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace);
 
     /* copy tables */
-    {   size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
+    {   size_t const chainSize = ZSTD_allocateChainTable(srcCCtx->appliedParams.cParams.strategy,
+                                                         srcCCtx->appliedParams.useRowMatchFinder,
+                                                         0 /* forDDSDict */)
+                                    ? ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog)
+                                    : 0;
         size_t const hSize =  (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
         int const h3log = srcCCtx->blockState.matchState.hashLog3;
         size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
 
-        memcpy(dstCCtx->blockState.matchState.hashTable,
+        ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable,
                srcCCtx->blockState.matchState.hashTable,
                hSize * sizeof(U32));
-        memcpy(dstCCtx->blockState.matchState.chainTable,
+        ZSTD_memcpy(dstCCtx->blockState.matchState.chainTable,
                srcCCtx->blockState.matchState.chainTable,
                chainSize * sizeof(U32));
-        memcpy(dstCCtx->blockState.matchState.hashTable3,
+        ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable3,
                srcCCtx->blockState.matchState.hashTable3,
                h3Size * sizeof(U32));
     }
@@ -1819,9 +2256,10 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
         dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
     }
     dstCCtx->dictID = srcCCtx->dictID;
+    dstCCtx->dictContentSize = srcCCtx->dictContentSize;
 
     /* copy block state */
-    memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
+    ZSTD_memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
 
     return 0;
 }
@@ -1834,7 +2272,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
 size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
 {
     ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
-    ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
+    ZSTD_buffered_policy_e const zbuff = srcCCtx->bufferedPolicy;
     ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
     if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
     fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
@@ -1861,7 +2299,7 @@ ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerVa
     assert((size & (ZSTD_ROWSIZE-1)) == 0);  /* multiple of ZSTD_ROWSIZE */
     assert(size < (1U<<31));   /* can be casted to int */
 
-#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
+#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
     /* To validate that the table re-use logic is sound, and that we don't
      * access table space that we haven't cleaned, we re-"poison" the table
      * space every time we mark it dirty.
@@ -1905,7 +2343,7 @@ static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* par
         ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
     }
 
-    if (params->cParams.strategy != ZSTD_fast) {
+    if (ZSTD_allocateChainTable(params->cParams.strategy, params->useRowMatchFinder, (U32)ms->dedicatedDictSearch)) {
         U32 const chainSize = (U32)1 << params->cParams.chainLog;
         if (params->cParams.strategy == ZSTD_btlazy2)
             ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue);
@@ -1942,9 +2380,9 @@ void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
         ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
         mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv);
     }
-    if (seqStorePtr->longLengthID==1)
+    if (seqStorePtr->longLengthType==ZSTD_llt_literalLength)
         llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
-    if (seqStorePtr->longLengthID==2)
+    if (seqStorePtr->longLengthType==ZSTD_llt_matchLength)
         mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
 }
 
@@ -1958,10 +2396,158 @@ static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams)
     return (cctxParams->targetCBlockSize != 0);
 }
 
-/* ZSTD_compressSequences_internal():
- * actually compresses both literals and sequences */
+/* ZSTD_blockSplitterEnabled():
+ * Returns if block splitting param is being used
+ * If used, compression will do best effort to split a block in order to improve compression ratio.
+ * Returns 1 if true, 0 otherwise. */
+static int ZSTD_blockSplitterEnabled(ZSTD_CCtx_params* cctxParams)
+{
+    DEBUGLOG(5, "ZSTD_blockSplitterEnabled(splitBlocks=%d)", cctxParams->splitBlocks);
+    return (cctxParams->splitBlocks != 0);
+}
+
+/* Type returned by ZSTD_buildSequencesStatistics containing finalized symbol encoding types
+ * and size of the sequences statistics
+ */
+typedef struct {
+    U32 LLtype;
+    U32 Offtype;
+    U32 MLtype;
+    size_t size;
+    size_t lastCountSize; /* Accounts for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */
+} ZSTD_symbolEncodingTypeStats_t;
+
+/* ZSTD_buildSequencesStatistics():
+ * Returns a ZSTD_symbolEncodingTypeStats_t, or a zstd error code in the `size` field.
+ * Modifies `nextEntropy` to have the appropriate values as a side effect.
+ * nbSeq must be greater than 0.
+ *
+ * entropyWkspSize must be of size at least ENTROPY_WORKSPACE_SIZE - (MaxSeq + 1)*sizeof(U32)
+ */
+static ZSTD_symbolEncodingTypeStats_t
+ZSTD_buildSequencesStatistics(seqStore_t* seqStorePtr, size_t nbSeq,
+                        const ZSTD_fseCTables_t* prevEntropy, ZSTD_fseCTables_t* nextEntropy,
+                              BYTE* dst, const BYTE* const dstEnd,
+                              ZSTD_strategy strategy, unsigned* countWorkspace,
+                              void* entropyWorkspace, size_t entropyWkspSize) {
+    BYTE* const ostart = dst;
+    const BYTE* const oend = dstEnd;
+    BYTE* op = ostart;
+    FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable;
+    FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable;
+    FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable;
+    const BYTE* const ofCodeTable = seqStorePtr->ofCode;
+    const BYTE* const llCodeTable = seqStorePtr->llCode;
+    const BYTE* const mlCodeTable = seqStorePtr->mlCode;
+    ZSTD_symbolEncodingTypeStats_t stats;
+
+    stats.lastCountSize = 0;
+    /* convert length/distances into codes */
+    ZSTD_seqToCodes(seqStorePtr);
+    assert(op <= oend);
+    assert(nbSeq != 0); /* ZSTD_selectEncodingType() divides by nbSeq */
+    /* build CTable for Literal Lengths */
+    {   unsigned max = MaxLL;
+        size_t const mostFrequent = HIST_countFast_wksp(countWorkspace, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize);   /* can't fail */
+        DEBUGLOG(5, "Building LL table");
+        nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
+        stats.LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode,
+                                        countWorkspace, max, mostFrequent, nbSeq,
+                                        LLFSELog, prevEntropy->litlengthCTable,
+                                        LL_defaultNorm, LL_defaultNormLog,
+                                        ZSTD_defaultAllowed, strategy);
+        assert(set_basic < set_compressed && set_rle < set_compressed);
+        assert(!(stats.LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+        {   size_t const countSize = ZSTD_buildCTable(
+                op, (size_t)(oend - op),
+                CTable_LitLength, LLFSELog, (symbolEncodingType_e)stats.LLtype,
+                countWorkspace, max, llCodeTable, nbSeq,
+                LL_defaultNorm, LL_defaultNormLog, MaxLL,
+                prevEntropy->litlengthCTable,
+                sizeof(prevEntropy->litlengthCTable),
+                entropyWorkspace, entropyWkspSize);
+            if (ZSTD_isError(countSize)) {
+                DEBUGLOG(3, "ZSTD_buildCTable for LitLens failed");
+                stats.size = countSize;
+                return stats;
+            }
+            if (stats.LLtype == set_compressed)
+                stats.lastCountSize = countSize;
+            op += countSize;
+            assert(op <= oend);
+    }   }
+    /* build CTable for Offsets */
+    {   unsigned max = MaxOff;
+        size_t const mostFrequent = HIST_countFast_wksp(
+            countWorkspace, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize);  /* can't fail */
+        /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
+        ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
+        DEBUGLOG(5, "Building OF table");
+        nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
+        stats.Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode,
+                                        countWorkspace, max, mostFrequent, nbSeq,
+                                        OffFSELog, prevEntropy->offcodeCTable,
+                                        OF_defaultNorm, OF_defaultNormLog,
+                                        defaultPolicy, strategy);
+        assert(!(stats.Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+        {   size_t const countSize = ZSTD_buildCTable(
+                op, (size_t)(oend - op),
+                CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)stats.Offtype,
+                countWorkspace, max, ofCodeTable, nbSeq,
+                OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
+                prevEntropy->offcodeCTable,
+                sizeof(prevEntropy->offcodeCTable),
+                entropyWorkspace, entropyWkspSize);
+            if (ZSTD_isError(countSize)) {
+                DEBUGLOG(3, "ZSTD_buildCTable for Offsets failed");
+                stats.size = countSize;
+                return stats;
+            }
+            if (stats.Offtype == set_compressed)
+                stats.lastCountSize = countSize;
+            op += countSize;
+            assert(op <= oend);
+    }   }
+    /* build CTable for MatchLengths */
+    {   unsigned max = MaxML;
+        size_t const mostFrequent = HIST_countFast_wksp(
+            countWorkspace, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize);   /* can't fail */
+        DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
+        nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
+        stats.MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode,
+                                        countWorkspace, max, mostFrequent, nbSeq,
+                                        MLFSELog, prevEntropy->matchlengthCTable,
+                                        ML_defaultNorm, ML_defaultNormLog,
+                                        ZSTD_defaultAllowed, strategy);
+        assert(!(stats.MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
+        {   size_t const countSize = ZSTD_buildCTable(
+                op, (size_t)(oend - op),
+                CTable_MatchLength, MLFSELog, (symbolEncodingType_e)stats.MLtype,
+                countWorkspace, max, mlCodeTable, nbSeq,
+                ML_defaultNorm, ML_defaultNormLog, MaxML,
+                prevEntropy->matchlengthCTable,
+                sizeof(prevEntropy->matchlengthCTable),
+                entropyWorkspace, entropyWkspSize);
+            if (ZSTD_isError(countSize)) {
+                DEBUGLOG(3, "ZSTD_buildCTable for MatchLengths failed");
+                stats.size = countSize;
+                return stats;
+            }
+            if (stats.MLtype == set_compressed)
+                stats.lastCountSize = countSize;
+            op += countSize;
+            assert(op <= oend);
+    }   }
+    stats.size = (size_t)(op-ostart);
+    return stats;
+}
+
+/* ZSTD_entropyCompressSeqStore_internal():
+ * compresses both literals and sequences
+ * Returns compressed size of block, or a zstd error.
+ */
 MEM_STATIC size_t
-ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
+ZSTD_entropyCompressSeqStore_internal(seqStore_t* seqStorePtr,
                           const ZSTD_entropyCTables_t* prevEntropy,
                                 ZSTD_entropyCTables_t* nextEntropy,
                           const ZSTD_CCtx_params* cctxParams,
@@ -1971,24 +2557,26 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
 {
     const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
     ZSTD_strategy const strategy = cctxParams->cParams.strategy;
-    unsigned count[MaxSeq+1];
+    unsigned* count = (unsigned*)entropyWorkspace;
     FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable;
     FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable;
     FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable;
-    U32 LLtype, Offtype, MLtype;   /* compressed, raw or rle */
     const seqDef* const sequences = seqStorePtr->sequencesStart;
+    const size_t nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
     const BYTE* const ofCodeTable = seqStorePtr->ofCode;
     const BYTE* const llCodeTable = seqStorePtr->llCode;
     const BYTE* const mlCodeTable = seqStorePtr->mlCode;
     BYTE* const ostart = (BYTE*)dst;
     BYTE* const oend = ostart + dstCapacity;
     BYTE* op = ostart;
-    size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
-    BYTE* seqHead;
-    BYTE* lastNCount = NULL;
+    size_t lastCountSize;
 
-    DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq);
+    entropyWorkspace = count + (MaxSeq + 1);
+    entropyWkspSize -= (MaxSeq + 1) * sizeof(*count);
+
+    DEBUGLOG(4, "ZSTD_entropyCompressSeqStore_internal (nbSeq=%zu)", nbSeq);
     ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
+    assert(entropyWkspSize >= HUF_WORKSPACE_SIZE);
 
     /* Compress literals */
     {   const BYTE* const literals = seqStorePtr->litStart;
@@ -2023,132 +2611,57 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
     assert(op <= oend);
     if (nbSeq==0) {
         /* Copy the old tables over as if we repeated them */
-        memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
+        ZSTD_memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
         return (size_t)(op - ostart);
     }
+    {
+        ZSTD_symbolEncodingTypeStats_t stats;
+        BYTE* seqHead = op++;
+        /* build stats for sequences */
+        stats = ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq,
+                                             &prevEntropy->fse, &nextEntropy->fse,
+                                              op, oend,
+                                              strategy, count,
+                                              entropyWorkspace, entropyWkspSize);
+        FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!");
+        *seqHead = (BYTE)((stats.LLtype<<6) + (stats.Offtype<<4) + (stats.MLtype<<2));
+        lastCountSize = stats.lastCountSize;
+        op += stats.size;
+    }
 
-    /* seqHead : flags for FSE encoding type */
-    seqHead = op++;
-    assert(op <= oend);
-
-    /* convert length/distances into codes */
-    ZSTD_seqToCodes(seqStorePtr);
-    /* build CTable for Literal Lengths */
-    {   unsigned max = MaxLL;
-        size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize);   /* can't fail */
-        DEBUGLOG(5, "Building LL table");
-        nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode;
-        LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode,
-                                        count, max, mostFrequent, nbSeq,
-                                        LLFSELog, prevEntropy->fse.litlengthCTable,
-                                        LL_defaultNorm, LL_defaultNormLog,
-                                        ZSTD_defaultAllowed, strategy);
-        assert(set_basic < set_compressed && set_rle < set_compressed);
-        assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
-        {   size_t const countSize = ZSTD_buildCTable(
-                op, (size_t)(oend - op),
-                CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
-                count, max, llCodeTable, nbSeq,
-                LL_defaultNorm, LL_defaultNormLog, MaxLL,
-                prevEntropy->fse.litlengthCTable,
-                sizeof(prevEntropy->fse.litlengthCTable),
-                entropyWorkspace, entropyWkspSize);
-            FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed");
-            if (LLtype == set_compressed)
-                lastNCount = op;
-            op += countSize;
-            assert(op <= oend);
-    }   }
-    /* build CTable for Offsets */
-    {   unsigned max = MaxOff;
-        size_t const mostFrequent = HIST_countFast_wksp(
-            count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize);  /* can't fail */
-        /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
-        ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
-        DEBUGLOG(5, "Building OF table");
-        nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode;
-        Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode,
-                                        count, max, mostFrequent, nbSeq,
-                                        OffFSELog, prevEntropy->fse.offcodeCTable,
-                                        OF_defaultNorm, OF_defaultNormLog,
-                                        defaultPolicy, strategy);
-        assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
-        {   size_t const countSize = ZSTD_buildCTable(
-                op, (size_t)(oend - op),
-                CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
-                count, max, ofCodeTable, nbSeq,
-                OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
-                prevEntropy->fse.offcodeCTable,
-                sizeof(prevEntropy->fse.offcodeCTable),
-                entropyWorkspace, entropyWkspSize);
-            FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed");
-            if (Offtype == set_compressed)
-                lastNCount = op;
-            op += countSize;
-            assert(op <= oend);
-    }   }
-    /* build CTable for MatchLengths */
-    {   unsigned max = MaxML;
-        size_t const mostFrequent = HIST_countFast_wksp(
-            count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize);   /* can't fail */
-        DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
-        nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode;
-        MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode,
-                                        count, max, mostFrequent, nbSeq,
-                                        MLFSELog, prevEntropy->fse.matchlengthCTable,
-                                        ML_defaultNorm, ML_defaultNormLog,
-                                        ZSTD_defaultAllowed, strategy);
-        assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
-        {   size_t const countSize = ZSTD_buildCTable(
-                op, (size_t)(oend - op),
-                CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
-                count, max, mlCodeTable, nbSeq,
-                ML_defaultNorm, ML_defaultNormLog, MaxML,
-                prevEntropy->fse.matchlengthCTable,
-                sizeof(prevEntropy->fse.matchlengthCTable),
-                entropyWorkspace, entropyWkspSize);
-            FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed");
-            if (MLtype == set_compressed)
-                lastNCount = op;
-            op += countSize;
-            assert(op <= oend);
-    }   }
-
-    *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
-
-    {   size_t const bitstreamSize = ZSTD_encodeSequences(
-                                        op, (size_t)(oend - op),
-                                        CTable_MatchLength, mlCodeTable,
-                                        CTable_OffsetBits, ofCodeTable,
-                                        CTable_LitLength, llCodeTable,
-                                        sequences, nbSeq,
-                                        longOffsets, bmi2);
-        FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed");
-        op += bitstreamSize;
-        assert(op <= oend);
-        /* zstd versions <= 1.3.4 mistakenly report corruption when
-         * FSE_readNCount() receives a buffer < 4 bytes.
-         * Fixed by https://github.com/facebook/zstd/pull/1146.
-         * This can happen when the last set_compressed table present is 2
-         * bytes and the bitstream is only one byte.
-         * In this exceedingly rare case, we will simply emit an uncompressed
-         * block, since it isn't worth optimizing.
-         */
-        if (lastNCount && (op - lastNCount) < 4) {
-            /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
-            assert(op - lastNCount == 3);
-            DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
-                        "emitting an uncompressed block.");
-            return 0;
-        }
-    }
+    {   size_t const bitstreamSize = ZSTD_encodeSequences(
+                                        op, (size_t)(oend - op),
+                                        CTable_MatchLength, mlCodeTable,
+                                        CTable_OffsetBits, ofCodeTable,
+                                        CTable_LitLength, llCodeTable,
+                                        sequences, nbSeq,
+                                        longOffsets, bmi2);
+        FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed");
+        op += bitstreamSize;
+        assert(op <= oend);
+        /* zstd versions <= 1.3.4 mistakenly report corruption when
+         * FSE_readNCount() receives a buffer < 4 bytes.
+         * Fixed by https://github.com/facebook/zstd/pull/1146.
+         * This can happen when the last set_compressed table present is 2
+         * bytes and the bitstream is only one byte.
+         * In this exceedingly rare case, we will simply emit an uncompressed
+         * block, since it isn't worth optimizing.
+         */
+        if (lastCountSize && (lastCountSize + bitstreamSize) < 4) {
+            /* lastCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
+            assert(lastCountSize + bitstreamSize == 3);
+            DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
+                        "emitting an uncompressed block.");
+            return 0;
+        }
+    }
 
     DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart));
     return (size_t)(op - ostart);
 }
 
 MEM_STATIC size_t
-ZSTD_compressSequences(seqStore_t* seqStorePtr,
+ZSTD_entropyCompressSeqStore(seqStore_t* seqStorePtr,
                        const ZSTD_entropyCTables_t* prevEntropy,
                              ZSTD_entropyCTables_t* nextEntropy,
                        const ZSTD_CCtx_params* cctxParams,
@@ -2157,7 +2670,7 @@ ZSTD_compressSequences(seqStore_t* seqStorePtr,
                              void* entropyWorkspace, size_t entropyWkspSize,
                              int bmi2)
 {
-    size_t const cSize = ZSTD_compressSequences_internal(
+    size_t const cSize = ZSTD_entropyCompressSeqStore_internal(
                             seqStorePtr, prevEntropy, nextEntropy, cctxParams,
                             dst, dstCapacity,
                             entropyWorkspace, entropyWkspSize, bmi2);
@@ -2167,22 +2680,22 @@ ZSTD_compressSequences(seqStore_t* seqStorePtr,
      */
     if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
         return 0;  /* block not compressed */
-    FORWARD_IF_ERROR(cSize, "ZSTD_compressSequences_internal failed");
+    FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSeqStore_internal failed");
 
     /* Check compressibility */
     {   size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy);
         if (cSize >= maxCSize) return 0;  /* block not compressed */
     }
-
+    DEBUGLOG(4, "ZSTD_entropyCompressSeqStore() cSize: %zu", cSize);
     return cSize;
 }
 
 /* ZSTD_selectBlockCompressor() :
  * Not static, but internal use only (used by long distance matcher)
  * assumption : strat is a valid strategy */
-ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode)
+ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_useRowMatchFinderMode_e useRowMatchFinder, ZSTD_dictMode_e dictMode)
 {
-    static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = {
+    static const ZSTD_blockCompressor blockCompressor[4][ZSTD_STRATEGY_MAX+1] = {
         { ZSTD_compressBlock_fast  /* default for 0 */,
           ZSTD_compressBlock_fast,
           ZSTD_compressBlock_doubleFast,
@@ -2212,13 +2725,44 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMo
           ZSTD_compressBlock_btlazy2_dictMatchState,
           ZSTD_compressBlock_btopt_dictMatchState,
           ZSTD_compressBlock_btultra_dictMatchState,
-          ZSTD_compressBlock_btultra_dictMatchState }
+          ZSTD_compressBlock_btultra_dictMatchState },
+        { NULL  /* default for 0 */,
+          NULL,
+          NULL,
+          ZSTD_compressBlock_greedy_dedicatedDictSearch,
+          ZSTD_compressBlock_lazy_dedicatedDictSearch,
+          ZSTD_compressBlock_lazy2_dedicatedDictSearch,
+          NULL,
+          NULL,
+          NULL,
+          NULL }
     };
     ZSTD_blockCompressor selectedCompressor;
     ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
 
     assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
-    selectedCompressor = blockCompressor[(int)dictMode][(int)strat];
+    DEBUGLOG(4, "Selected block compressor: dictMode=%d strat=%d rowMatchfinder=%d", (int)dictMode, (int)strat, (int)useRowMatchFinder);
+    if (ZSTD_rowMatchFinderUsed(strat, useRowMatchFinder)) {
+        static const ZSTD_blockCompressor rowBasedBlockCompressors[4][3] = {
+            { ZSTD_compressBlock_greedy_row,
+            ZSTD_compressBlock_lazy_row,
+            ZSTD_compressBlock_lazy2_row },
+            { ZSTD_compressBlock_greedy_extDict_row,
+            ZSTD_compressBlock_lazy_extDict_row,
+            ZSTD_compressBlock_lazy2_extDict_row },
+            { ZSTD_compressBlock_greedy_dictMatchState_row,
+            ZSTD_compressBlock_lazy_dictMatchState_row,
+            ZSTD_compressBlock_lazy2_dictMatchState_row },
+            { ZSTD_compressBlock_greedy_dedicatedDictSearch_row,
+            ZSTD_compressBlock_lazy_dedicatedDictSearch_row,
+            ZSTD_compressBlock_lazy2_dedicatedDictSearch_row }
+        };
+        DEBUGLOG(4, "Selecting a row-based matchfinder");
+        assert(useRowMatchFinder != ZSTD_urm_auto);
+        selectedCompressor = rowBasedBlockCompressors[(int)dictMode][(int)strat - (int)ZSTD_greedy];
+    } else {
+        selectedCompressor = blockCompressor[(int)dictMode][(int)strat];
+    }
     assert(selectedCompressor != NULL);
     return selectedCompressor;
 }
@@ -2226,7 +2770,7 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMo
 static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
                                    const BYTE* anchor, size_t lastLLSize)
 {
-    memcpy(seqStorePtr->lit, anchor, lastLLSize);
+    ZSTD_memcpy(seqStorePtr->lit, anchor, lastLLSize);
     seqStorePtr->lit += lastLLSize;
 }
 
@@ -2234,7 +2778,7 @@ void ZSTD_resetSeqStore(seqStore_t* ssPtr)
 {
     ssPtr->lit = ssPtr->litStart;
     ssPtr->sequences = ssPtr->sequencesStart;
-    ssPtr->longLengthID = 0;
+    ssPtr->longLengthType = ZSTD_llt_none;
 }
 
 typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e;
@@ -2247,7 +2791,11 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
     /* Assert that we have correctly flushed the ctx params into the ms's copy */
     ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams);
     if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
-        ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch);
+        if (zc->appliedParams.cParams.strategy >= ZSTD_btopt) {
+            ZSTD_ldm_skipRawSeqStoreBytes(&zc->externSeqStore, srcSize);
+        } else {
+            ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch);
+        }
         return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */
     }
     ZSTD_resetSeqStore(&(zc->seqStore));
@@ -2263,10 +2811,10 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
     /* limited update after a very long match */
     {   const BYTE* const base = ms->window.base;
         const BYTE* const istart = (const BYTE*)src;
-        const U32 current = (U32)(istart-base);
+        const U32 curr = (U32)(istart-base);
         if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1));   /* ensure no overflow */
-        if (current > ms->nextToUpdate + 384)
-            ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384));
+        if (curr > ms->nextToUpdate + 384)
+            ms->nextToUpdate = curr - MIN(192, (U32)(curr - ms->nextToUpdate - 384));
     }
 
     /* select and store sequences */
@@ -2283,10 +2831,11 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
                 ZSTD_ldm_blockCompress(&zc->externSeqStore,
                                        ms, &zc->seqStore,
                                        zc->blockState.nextCBlock->rep,
+                                       zc->appliedParams.useRowMatchFinder,
                                        src, srcSize);
             assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
         } else if (zc->appliedParams.ldmParams.enableLdm) {
-            rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0};
+            rawSeqStore_t ldmSeqStore = kNullRawSeqStore;
 
             ldmSeqStore.seq = zc->ldmSequences;
             ldmSeqStore.capacity = zc->maxNbLdmSequences;
@@ -2299,10 +2848,14 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
                 ZSTD_ldm_blockCompress(&ldmSeqStore,
                                        ms, &zc->seqStore,
                                        zc->blockState.nextCBlock->rep,
+                                       zc->appliedParams.useRowMatchFinder,
                                        src, srcSize);
             assert(ldmSeqStore.pos == ldmSeqStore.size);
         } else {   /* not long range mode */
-            ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode);
+            ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy,
+                                                                                    zc->appliedParams.useRowMatchFinder,
+                                                                                    dictMode);
+            ms->ldmSeqStore = NULL;
             lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize);
         }
         {   const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize;
@@ -2314,59 +2867,72 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
 static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc)
 {
     const seqStore_t* seqStore = ZSTD_getSeqStore(zc);
-    const seqDef* seqs = seqStore->sequencesStart;
-    size_t seqsSize = seqStore->sequences - seqs;
+    const seqDef* seqStoreSeqs = seqStore->sequencesStart;
+    size_t seqStoreSeqSize = seqStore->sequences - seqStoreSeqs;
+    size_t seqStoreLiteralsSize = (size_t)(seqStore->lit - seqStore->litStart);
+    size_t literalsRead = 0;
+    size_t lastLLSize;
 
     ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex];
-    size_t i; size_t position; int repIdx;
+    size_t i;
+    repcodes_t updatedRepcodes;
 
     assert(zc->seqCollector.seqIndex + 1 < zc->seqCollector.maxSequences);
-    for (i = 0, position = 0; i < seqsSize; ++i) {
-        outSeqs[i].offset = seqs[i].offset;
-        outSeqs[i].litLength = seqs[i].litLength;
-        outSeqs[i].matchLength = seqs[i].matchLength + MINMATCH;
+    /* Ensure we have enough space for last literals "sequence" */
+    assert(zc->seqCollector.maxSequences >= seqStoreSeqSize + 1);
+    ZSTD_memcpy(updatedRepcodes.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t));
+    for (i = 0; i < seqStoreSeqSize; ++i) {
+        U32 rawOffset = seqStoreSeqs[i].offset - ZSTD_REP_NUM;
+        outSeqs[i].litLength = seqStoreSeqs[i].litLength;
+        outSeqs[i].matchLength = seqStoreSeqs[i].matchLength + MINMATCH;
+        outSeqs[i].rep = 0;
 
         if (i == seqStore->longLengthPos) {
-            if (seqStore->longLengthID == 1) {
+            if (seqStore->longLengthType == ZSTD_llt_literalLength) {
                 outSeqs[i].litLength += 0x10000;
-            } else if (seqStore->longLengthID == 2) {
+            } else if (seqStore->longLengthType == ZSTD_llt_matchLength) {
                 outSeqs[i].matchLength += 0x10000;
             }
         }
 
-        if (outSeqs[i].offset <= ZSTD_REP_NUM) {
-            outSeqs[i].rep = outSeqs[i].offset;
-            repIdx = (unsigned int)i - outSeqs[i].offset;
-
-            if (outSeqs[i].litLength == 0) {
-                if (outSeqs[i].offset < 3) {
-                    --repIdx;
+        if (seqStoreSeqs[i].offset <= ZSTD_REP_NUM) {
+            /* Derive the correct offset corresponding to a repcode */
+            outSeqs[i].rep = seqStoreSeqs[i].offset;
+            if (outSeqs[i].litLength != 0) {
+                rawOffset = updatedRepcodes.rep[outSeqs[i].rep - 1];
+            } else {
+                if (outSeqs[i].rep == 3) {
+                    rawOffset = updatedRepcodes.rep[0] - 1;
                 } else {
-                    repIdx = (unsigned int)i - 1;
+                    rawOffset = updatedRepcodes.rep[outSeqs[i].rep];
                 }
-                ++outSeqs[i].rep;
-            }
-            assert(repIdx >= -3);
-            outSeqs[i].offset = repIdx >= 0 ? outSeqs[repIdx].offset : repStartValue[-repIdx - 1];
-            if (outSeqs[i].rep == 4) {
-                --outSeqs[i].offset;
             }
-        } else {
-            outSeqs[i].offset -= ZSTD_REP_NUM;
         }
-
-        position += outSeqs[i].litLength;
-        outSeqs[i].matchPos = (unsigned int)position;
-        position += outSeqs[i].matchLength;
+        outSeqs[i].offset = rawOffset;
+        /* seqStoreSeqs[i].offset == offCode+1, and ZSTD_updateRep() expects offCode
+           so we provide seqStoreSeqs[i].offset - 1 */
+        updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep,
+                                         seqStoreSeqs[i].offset - 1,
+                                         seqStoreSeqs[i].litLength == 0);
+        literalsRead += outSeqs[i].litLength;
     }
-    zc->seqCollector.seqIndex += seqsSize;
+    /* Insert last literals (if any exist) in the block as a sequence with ml == off == 0.
+     * If there are no last literals, then we'll emit (of: 0, ml: 0, ll: 0), which is a marker
+     * for the block boundary, according to the API.
+     */
+    assert(seqStoreLiteralsSize >= literalsRead);
+    lastLLSize = seqStoreLiteralsSize - literalsRead;
+    outSeqs[i].litLength = (U32)lastLLSize;
+    outSeqs[i].matchLength = outSeqs[i].offset = outSeqs[i].rep = 0;
+    seqStoreSeqSize++;
+    zc->seqCollector.seqIndex += seqStoreSeqSize;
 }
 
-size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
-    size_t outSeqsSize, const void* src, size_t srcSize)
+size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
+                              size_t outSeqsSize, const void* src, size_t srcSize)
 {
     const size_t dstCapacity = ZSTD_compressBound(srcSize);
-    void* dst = ZSTD_malloc(dstCapacity, ZSTD_defaultCMem);
+    void* dst = ZSTD_customMalloc(dstCapacity, ZSTD_defaultCMem);
     SeqCollector seqCollector;
 
     RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!");
@@ -2378,16 +2944,47 @@ size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
     zc->seqCollector = seqCollector;
 
     ZSTD_compress2(zc, dst, dstCapacity, src, srcSize);
-    ZSTD_free(dst, ZSTD_defaultCMem);
+    ZSTD_customFree(dst, ZSTD_defaultCMem);
     return zc->seqCollector.seqIndex;
 }
 
-/* Returns true if the given block is a RLE block */
-static int ZSTD_isRLE(const BYTE *ip, size_t length) {
+size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize) {
+    size_t in = 0;
+    size_t out = 0;
+    for (; in < seqsSize; ++in) {
+        if (sequences[in].offset == 0 && sequences[in].matchLength == 0) {
+            if (in != seqsSize - 1) {
+                sequences[in+1].litLength += sequences[in].litLength;
+            }
+        } else {
+            sequences[out] = sequences[in];
+            ++out;
+        }
+    }
+    return out;
+}
+
+/* Unrolled loop to read four size_ts of input at a time. Returns 1 if is RLE, 0 if not. */
+static int ZSTD_isRLE(const BYTE* src, size_t length) {
+    const BYTE* ip = src;
+    const BYTE value = ip[0];
+    const size_t valueST = (size_t)((U64)value * 0x0101010101010101ULL);
+    const size_t unrollSize = sizeof(size_t) * 4;
+    const size_t unrollMask = unrollSize - 1;
+    const size_t prefixLength = length & unrollMask;
     size_t i;
-    if (length < 2) return 1;
-    for (i = 1; i < length; ++i) {
-        if (ip[0] != ip[i]) return 0;
+    size_t u;
+    if (length == 1) return 1;
+    /* Check if prefix is RLE first before using unrolled loop */
+    if (prefixLength && ZSTD_count(ip+1, ip, ip+prefixLength) != prefixLength-1) {
+        return 0;
+    }
+    for (i = prefixLength; i != length; i += unrollSize) {
+        for (u = 0; u < unrollSize; u += sizeof(size_t)) {
+            if (MEM_readST(ip + i + u) != valueST) {
+                return 0;
+            }
+        }
     }
     return 1;
 }
@@ -2404,11 +3001,713 @@ static int ZSTD_maybeRLE(seqStore_t const* seqStore)
     return nbSeqs < 4 && nbLits < 10;
 }
 
-static void ZSTD_confirmRepcodesAndEntropyTables(ZSTD_CCtx* zc)
+static void ZSTD_blockState_confirmRepcodesAndEntropyTables(ZSTD_blockState_t* const bs)
+{
+    ZSTD_compressedBlockState_t* const tmp = bs->prevCBlock;
+    bs->prevCBlock = bs->nextCBlock;
+    bs->nextCBlock = tmp;
+}
+
+/* Writes the block header */
+static void writeBlockHeader(void* op, size_t cSize, size_t blockSize, U32 lastBlock) {
+    U32 const cBlockHeader = cSize == 1 ?
+                        lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) :
+                        lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
+    MEM_writeLE24(op, cBlockHeader);
+    DEBUGLOG(3, "writeBlockHeader: cSize: %zu blockSize: %zu lastBlock: %u", cSize, blockSize, lastBlock);
+}
+
+/** ZSTD_buildBlockEntropyStats_literals() :
+ *  Builds entropy for the literals.
+ *  Stores literals block type (raw, rle, compressed, repeat) and
+ *  huffman description table to hufMetadata.
+ *  Requires ENTROPY_WORKSPACE_SIZE workspace
+ *  @return : size of huffman description table or error code */
+static size_t ZSTD_buildBlockEntropyStats_literals(void* const src, size_t srcSize,
+                                            const ZSTD_hufCTables_t* prevHuf,
+                                                  ZSTD_hufCTables_t* nextHuf,
+                                                  ZSTD_hufCTablesMetadata_t* hufMetadata,
+                                                  const int disableLiteralsCompression,
+                                                  void* workspace, size_t wkspSize)
+{
+    BYTE* const wkspStart = (BYTE*)workspace;
+    BYTE* const wkspEnd = wkspStart + wkspSize;
+    BYTE* const countWkspStart = wkspStart;
+    unsigned* const countWksp = (unsigned*)workspace;
+    const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned);
+    BYTE* const nodeWksp = countWkspStart + countWkspSize;
+    const size_t nodeWkspSize = wkspEnd-nodeWksp;
+    unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX;
+    unsigned huffLog = HUF_TABLELOG_DEFAULT;
+    HUF_repeat repeat = prevHuf->repeatMode;
+    DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_literals (srcSize=%zu)", srcSize);
+
+    /* Prepare nextEntropy assuming reusing the existing table */
+    ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+
+    if (disableLiteralsCompression) {
+        DEBUGLOG(5, "set_basic - disabled");
+        hufMetadata->hType = set_basic;
+        return 0;
+    }
+
+    /* small ? don't even attempt compression (speed opt) */
+#ifndef COMPRESS_LITERALS_SIZE_MIN
+#define COMPRESS_LITERALS_SIZE_MIN 63
+#endif
+    {   size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
+        if (srcSize <= minLitSize) {
+            DEBUGLOG(5, "set_basic - too small");
+            hufMetadata->hType = set_basic;
+            return 0;
+        }
+    }
+
+    /* Scan input and build symbol stats */
+    {   size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)src, srcSize, workspace, wkspSize);
+        FORWARD_IF_ERROR(largest, "HIST_count_wksp failed");
+        if (largest == srcSize) {
+            DEBUGLOG(5, "set_rle");
+            hufMetadata->hType = set_rle;
+            return 0;
+        }
+        if (largest <= (srcSize >> 7)+4) {
+            DEBUGLOG(5, "set_basic - no gain");
+            hufMetadata->hType = set_basic;
+            return 0;
+        }
+    }
+
+    /* Validate the previous Huffman table */
+    if (repeat == HUF_repeat_check && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) {
+        repeat = HUF_repeat_none;
+    }
+
+    /* Build Huffman Tree */
+    ZSTD_memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable));
+    huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
+    {   size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp,
+                                                    maxSymbolValue, huffLog,
+                                                    nodeWksp, nodeWkspSize);
+        FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp");
+        huffLog = (U32)maxBits;
+        {   /* Build and write the CTable */
+            size_t const newCSize = HUF_estimateCompressedSize(
+                    (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue);
+            size_t const hSize = HUF_writeCTable_wksp(
+                    hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer),
+                    (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog,
+                    nodeWksp, nodeWkspSize);
+            /* Check against repeating the previous CTable */
+            if (repeat != HUF_repeat_none) {
+                size_t const oldCSize = HUF_estimateCompressedSize(
+                        (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue);
+                if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) {
+                    DEBUGLOG(5, "set_repeat - smaller");
+                    ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+                    hufMetadata->hType = set_repeat;
+                    return 0;
+                }
+            }
+            if (newCSize + hSize >= srcSize) {
+                DEBUGLOG(5, "set_basic - no gains");
+                ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+                hufMetadata->hType = set_basic;
+                return 0;
+            }
+            DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize);
+            hufMetadata->hType = set_compressed;
+            nextHuf->repeatMode = HUF_repeat_check;
+            return hSize;
+        }
+    }
+}
+
+
+/* ZSTD_buildDummySequencesStatistics():
+ * Returns a ZSTD_symbolEncodingTypeStats_t with all encoding types as set_basic,
+ * and updates nextEntropy to the appropriate repeatMode.
+ */
+static ZSTD_symbolEncodingTypeStats_t
+ZSTD_buildDummySequencesStatistics(ZSTD_fseCTables_t* nextEntropy) {
+    ZSTD_symbolEncodingTypeStats_t stats = {set_basic, set_basic, set_basic, 0, 0};
+    nextEntropy->litlength_repeatMode = FSE_repeat_none;
+    nextEntropy->offcode_repeatMode = FSE_repeat_none;
+    nextEntropy->matchlength_repeatMode = FSE_repeat_none;
+    return stats;
+}
+
+/** ZSTD_buildBlockEntropyStats_sequences() :
+ *  Builds entropy for the sequences.
+ *  Stores symbol compression modes and fse table to fseMetadata.
+ *  Requires ENTROPY_WORKSPACE_SIZE wksp.
+ *  @return : size of fse tables or error code */
+static size_t ZSTD_buildBlockEntropyStats_sequences(seqStore_t* seqStorePtr,
+                                              const ZSTD_fseCTables_t* prevEntropy,
+                                                    ZSTD_fseCTables_t* nextEntropy,
+                                              const ZSTD_CCtx_params* cctxParams,
+                                                    ZSTD_fseCTablesMetadata_t* fseMetadata,
+                                                    void* workspace, size_t wkspSize)
 {
-    ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock;
-    zc->blockState.prevCBlock = zc->blockState.nextCBlock;
-    zc->blockState.nextCBlock = tmp;
+    ZSTD_strategy const strategy = cctxParams->cParams.strategy;
+    size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
+    BYTE* const ostart = fseMetadata->fseTablesBuffer;
+    BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer);
+    BYTE* op = ostart;
+    unsigned* countWorkspace = (unsigned*)workspace;
+    unsigned* entropyWorkspace = countWorkspace + (MaxSeq + 1);
+    size_t entropyWorkspaceSize = wkspSize - (MaxSeq + 1) * sizeof(*countWorkspace);
+    ZSTD_symbolEncodingTypeStats_t stats;
+
+    DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_sequences (nbSeq=%zu)", nbSeq);
+    stats = nbSeq != 0 ? ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq,
+                                          prevEntropy, nextEntropy, op, oend,
+                                          strategy, countWorkspace,
+                                          entropyWorkspace, entropyWorkspaceSize)
+                       : ZSTD_buildDummySequencesStatistics(nextEntropy);
+    FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!");
+    fseMetadata->llType = (symbolEncodingType_e) stats.LLtype;
+    fseMetadata->ofType = (symbolEncodingType_e) stats.Offtype;
+    fseMetadata->mlType = (symbolEncodingType_e) stats.MLtype;
+    fseMetadata->lastCountSize = stats.lastCountSize;
+    return stats.size;
+}
+
+
+/** ZSTD_buildBlockEntropyStats() :
+ *  Builds entropy for the block.
+ *  Requires workspace size ENTROPY_WORKSPACE_SIZE
+ *
+ *  @return : 0 on success or error code
+ */
+size_t ZSTD_buildBlockEntropyStats(seqStore_t* seqStorePtr,
+                             const ZSTD_entropyCTables_t* prevEntropy,
+                                   ZSTD_entropyCTables_t* nextEntropy,
+                             const ZSTD_CCtx_params* cctxParams,
+                                   ZSTD_entropyCTablesMetadata_t* entropyMetadata,
+                                   void* workspace, size_t wkspSize)
+{
+    size_t const litSize = seqStorePtr->lit - seqStorePtr->litStart;
+    entropyMetadata->hufMetadata.hufDesSize =
+        ZSTD_buildBlockEntropyStats_literals(seqStorePtr->litStart, litSize,
+                                            &prevEntropy->huf, &nextEntropy->huf,
+                                            &entropyMetadata->hufMetadata,
+                                            ZSTD_disableLiteralsCompression(cctxParams),
+                                            workspace, wkspSize);
+    FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildBlockEntropyStats_literals failed");
+    entropyMetadata->fseMetadata.fseTablesSize =
+        ZSTD_buildBlockEntropyStats_sequences(seqStorePtr,
+                                              &prevEntropy->fse, &nextEntropy->fse,
+                                              cctxParams,
+                                              &entropyMetadata->fseMetadata,
+                                              workspace, wkspSize);
+    FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildBlockEntropyStats_sequences failed");
+    return 0;
+}
+
+/* Returns the size estimate for the literals section (header + content) of a block */
+static size_t ZSTD_estimateBlockSize_literal(const BYTE* literals, size_t litSize,
+                                                const ZSTD_hufCTables_t* huf,
+                                                const ZSTD_hufCTablesMetadata_t* hufMetadata,
+                                                void* workspace, size_t wkspSize,
+                                                int writeEntropy)
+{
+    unsigned* const countWksp = (unsigned*)workspace;
+    unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX;
+    size_t literalSectionHeaderSize = 3 + (litSize >= 1 KB) + (litSize >= 16 KB);
+    U32 singleStream = litSize < 256;
+
+    if (hufMetadata->hType == set_basic) return litSize;
+    else if (hufMetadata->hType == set_rle) return 1;
+    else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) {
+        size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize);
+        if (ZSTD_isError(largest)) return litSize;
+        {   size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue);
+            if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize;
+            if (!singleStream) cLitSizeEstimate += 6; /* multi-stream huffman uses 6-byte jump table */
+            return cLitSizeEstimate + literalSectionHeaderSize;
+    }   }
+    assert(0); /* impossible */
+    return 0;
+}
+
+/* Returns the size estimate for the FSE-compressed symbols (of, ml, ll) of a block */
+static size_t ZSTD_estimateBlockSize_symbolType(symbolEncodingType_e type,
+                        const BYTE* codeTable, size_t nbSeq, unsigned maxCode,
+                        const FSE_CTable* fseCTable,
+                        const U32* additionalBits,
+                        short const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
+                        void* workspace, size_t wkspSize)
+{
+    unsigned* const countWksp = (unsigned*)workspace;
+    const BYTE* ctp = codeTable;
+    const BYTE* const ctStart = ctp;
+    const BYTE* const ctEnd = ctStart + nbSeq;
+    size_t cSymbolTypeSizeEstimateInBits = 0;
+    unsigned max = maxCode;
+
+    HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize);  /* can't fail */
+    if (type == set_basic) {
+        /* We selected this encoding type, so it must be valid. */
+        assert(max <= defaultMax);
+        (void)defaultMax;
+        cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max);
+    } else if (type == set_rle) {
+        cSymbolTypeSizeEstimateInBits = 0;
+    } else if (type == set_compressed || type == set_repeat) {
+        cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max);
+    }
+    if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) {
+        return nbSeq * 10;
+    }
+    while (ctp < ctEnd) {
+        if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp];
+        else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */
+        ctp++;
+    }
+    return cSymbolTypeSizeEstimateInBits >> 3;
+}
+
+/* Returns the size estimate for the sequences section (header + content) of a block */
+static size_t ZSTD_estimateBlockSize_sequences(const BYTE* ofCodeTable,
+                                                  const BYTE* llCodeTable,
+                                                  const BYTE* mlCodeTable,
+                                                  size_t nbSeq,
+                                                  const ZSTD_fseCTables_t* fseTables,
+                                                  const ZSTD_fseCTablesMetadata_t* fseMetadata,
+                                                  void* workspace, size_t wkspSize,
+                                                  int writeEntropy)
+{
+    size_t sequencesSectionHeaderSize = 1 /* seqHead */ + 1 /* min seqSize size */ + (nbSeq >= 128) + (nbSeq >= LONGNBSEQ);
+    size_t cSeqSizeEstimate = 0;
+    cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, nbSeq, MaxOff,
+                                         fseTables->offcodeCTable, NULL,
+                                         OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
+                                         workspace, wkspSize);
+    cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->llType, llCodeTable, nbSeq, MaxLL,
+                                         fseTables->litlengthCTable, LL_bits,
+                                         LL_defaultNorm, LL_defaultNormLog, MaxLL,
+                                         workspace, wkspSize);
+    cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, nbSeq, MaxML,
+                                         fseTables->matchlengthCTable, ML_bits,
+                                         ML_defaultNorm, ML_defaultNormLog, MaxML,
+                                         workspace, wkspSize);
+    if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize;
+    return cSeqSizeEstimate + sequencesSectionHeaderSize;
+}
+
+/* Returns the size estimate for a given stream of literals, of, ll, ml */
+static size_t ZSTD_estimateBlockSize(const BYTE* literals, size_t litSize,
+                                     const BYTE* ofCodeTable,
+                                     const BYTE* llCodeTable,
+                                     const BYTE* mlCodeTable,
+                                     size_t nbSeq,
+                                     const ZSTD_entropyCTables_t* entropy,
+                                     const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
+                                     void* workspace, size_t wkspSize,
+                                     int writeLitEntropy, int writeSeqEntropy) {
+    size_t const literalsSize = ZSTD_estimateBlockSize_literal(literals, litSize,
+                                                         &entropy->huf, &entropyMetadata->hufMetadata,
+                                                         workspace, wkspSize, writeLitEntropy);
+    size_t const seqSize = ZSTD_estimateBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,
+                                                         nbSeq, &entropy->fse, &entropyMetadata->fseMetadata,
+                                                         workspace, wkspSize, writeSeqEntropy);
+    return seqSize + literalsSize + ZSTD_blockHeaderSize;
+}
+
+/* Builds entropy statistics and uses them for blocksize estimation.
+ *
+ * Returns the estimated compressed size of the seqStore, or a zstd error.
+ */
+static size_t ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(seqStore_t* seqStore, const ZSTD_CCtx* zc) {
+    ZSTD_entropyCTablesMetadata_t entropyMetadata;
+    FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(seqStore,
+                    &zc->blockState.prevCBlock->entropy,
+                    &zc->blockState.nextCBlock->entropy,
+                    &zc->appliedParams,
+                    &entropyMetadata,
+                    zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), "");
+    return ZSTD_estimateBlockSize(seqStore->litStart, (size_t)(seqStore->lit - seqStore->litStart),
+                    seqStore->ofCode, seqStore->llCode, seqStore->mlCode,
+                    (size_t)(seqStore->sequences - seqStore->sequencesStart),
+                    &zc->blockState.nextCBlock->entropy, &entropyMetadata, zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE,
+                    (int)(entropyMetadata.hufMetadata.hType == set_compressed), 1);
+}
+
+/* Returns literals bytes represented in a seqStore */
+static size_t ZSTD_countSeqStoreLiteralsBytes(const seqStore_t* const seqStore) {
+    size_t literalsBytes = 0;
+    size_t const nbSeqs = seqStore->sequences - seqStore->sequencesStart;
+    size_t i;
+    for (i = 0; i < nbSeqs; ++i) {
+        seqDef seq = seqStore->sequencesStart[i];
+        literalsBytes += seq.litLength;
+        if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_literalLength) {
+            literalsBytes += 0x10000;
+        }
+    }
+    return literalsBytes;
+}
+
+/* Returns match bytes represented in a seqStore */
+static size_t ZSTD_countSeqStoreMatchBytes(const seqStore_t* const seqStore) {
+    size_t matchBytes = 0;
+    size_t const nbSeqs = seqStore->sequences - seqStore->sequencesStart;
+    size_t i;
+    for (i = 0; i < nbSeqs; ++i) {
+        seqDef seq = seqStore->sequencesStart[i];
+        matchBytes += seq.matchLength + MINMATCH;
+        if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_matchLength) {
+            matchBytes += 0x10000;
+        }
+    }
+    return matchBytes;
+}
+
+/* Derives the seqStore that is a chunk of the originalSeqStore from [startIdx, endIdx).
+ * Stores the result in resultSeqStore.
+ */
+static void ZSTD_deriveSeqStoreChunk(seqStore_t* resultSeqStore,
+                               const seqStore_t* originalSeqStore,
+                                     size_t startIdx, size_t endIdx) {
+    BYTE* const litEnd = originalSeqStore->lit;
+    size_t literalsBytes;
+    size_t literalsBytesPreceding = 0;
+
+    *resultSeqStore = *originalSeqStore;
+    if (startIdx > 0) {
+        resultSeqStore->sequences = originalSeqStore->sequencesStart + startIdx;
+        literalsBytesPreceding = ZSTD_countSeqStoreLiteralsBytes(resultSeqStore);
+    }
+
+    /* Move longLengthPos into the correct position if necessary */
+    if (originalSeqStore->longLengthType != ZSTD_llt_none) {
+        if (originalSeqStore->longLengthPos < startIdx || originalSeqStore->longLengthPos > endIdx) {
+            resultSeqStore->longLengthType = ZSTD_llt_none;
+        } else {
+            resultSeqStore->longLengthPos -= (U32)startIdx;
+        }
+    }
+    resultSeqStore->sequencesStart = originalSeqStore->sequencesStart + startIdx;
+    resultSeqStore->sequences = originalSeqStore->sequencesStart + endIdx;
+    literalsBytes = ZSTD_countSeqStoreLiteralsBytes(resultSeqStore);
+    resultSeqStore->litStart += literalsBytesPreceding;
+    if (endIdx == (size_t)(originalSeqStore->sequences - originalSeqStore->sequencesStart)) {
+        /* This accounts for possible last literals if the derived chunk reaches the end of the block */
+        resultSeqStore->lit = litEnd;
+    } else {
+        resultSeqStore->lit = resultSeqStore->litStart+literalsBytes;
+    }
+    resultSeqStore->llCode += startIdx;
+    resultSeqStore->mlCode += startIdx;
+    resultSeqStore->ofCode += startIdx;
+}
+
+/**
+ * Returns the raw offset represented by the combination of offCode, ll0, and repcode history.
+ * offCode must be an offCode representing a repcode, therefore in the range of [0, 2].
+ */
+static U32 ZSTD_resolveRepcodeToRawOffset(const U32 rep[ZSTD_REP_NUM], const U32 offCode, const U32 ll0) {
+    U32 const adjustedOffCode = offCode + ll0;
+    assert(offCode < ZSTD_REP_NUM);
+    if (adjustedOffCode == ZSTD_REP_NUM) {
+        /* litlength == 0 and offCode == 2 implies selection of first repcode - 1 */
+        assert(rep[0] > 0);
+        return rep[0] - 1;
+    }
+    return rep[adjustedOffCode];
+}
+
+/**
+ * ZSTD_seqStore_resolveOffCodes() reconciles any possible divergences in offset history that may arise
+ * due to emission of RLE/raw blocks that disturb the offset history, and replaces any repcodes within
+ * the seqStore that may be invalid.
+ *
+ * dRepcodes are updated as would be on the decompression side. cRepcodes are updated exactly in
+ * accordance with the seqStore.
+ */
+static void ZSTD_seqStore_resolveOffCodes(repcodes_t* const dRepcodes, repcodes_t* const cRepcodes,
+                                          seqStore_t* const seqStore, U32 const nbSeq) {
+    U32 idx = 0;
+    for (; idx < nbSeq; ++idx) {
+        seqDef* const seq = seqStore->sequencesStart + idx;
+        U32 const ll0 = (seq->litLength == 0);
+        U32 offCode = seq->offset - 1;
+        assert(seq->offset > 0);
+        if (offCode <= ZSTD_REP_MOVE) {
+            U32 const dRawOffset = ZSTD_resolveRepcodeToRawOffset(dRepcodes->rep, offCode, ll0);
+            U32 const cRawOffset = ZSTD_resolveRepcodeToRawOffset(cRepcodes->rep, offCode, ll0);
+            /* Adjust simulated decompression repcode history if we come across a mismatch. Replace
+             * the repcode with the offset it actually references, determined by the compression
+             * repcode history.
+             */
+            if (dRawOffset != cRawOffset) {
+                seq->offset = cRawOffset + ZSTD_REP_NUM;
+            }
+        }
+        /* Compression repcode history is always updated with values directly from the unmodified seqStore.
+         * Decompression repcode history may use modified seq->offset value taken from compression repcode history.
+         */
+        *dRepcodes = ZSTD_updateRep(dRepcodes->rep, seq->offset - 1, ll0);
+        *cRepcodes = ZSTD_updateRep(cRepcodes->rep, offCode, ll0);
+    }
+}
+
+/* ZSTD_compressSeqStore_singleBlock():
+ * Compresses a seqStore into a block with a block header, into the buffer dst.
+ *
+ * Returns the total size of that block (including header) or a ZSTD error code.
+ */
+static size_t ZSTD_compressSeqStore_singleBlock(ZSTD_CCtx* zc, seqStore_t* const seqStore,
+                                                repcodes_t* const dRep, repcodes_t* const cRep,
+                                                void* dst, size_t dstCapacity,
+                                                const void* src, size_t srcSize,
+                                                U32 lastBlock, U32 isPartition) {
+    const U32 rleMaxLength = 25;
+    BYTE* op = (BYTE*)dst;
+    const BYTE* ip = (const BYTE*)src;
+    size_t cSize;
+    size_t cSeqsSize;
+
+    /* In case of an RLE or raw block, the simulated decompression repcode history must be reset */
+    repcodes_t const dRepOriginal = *dRep;
+    if (isPartition)
+        ZSTD_seqStore_resolveOffCodes(dRep, cRep, seqStore, (U32)(seqStore->sequences - seqStore->sequencesStart));
+
+    cSeqsSize = ZSTD_entropyCompressSeqStore(seqStore,
+                &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
+                &zc->appliedParams,
+                op + ZSTD_blockHeaderSize, dstCapacity - ZSTD_blockHeaderSize,
+                srcSize,
+                zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
+                zc->bmi2);
+    FORWARD_IF_ERROR(cSeqsSize, "ZSTD_entropyCompressSeqStore failed!");
+
+    if (!zc->isFirstBlock &&
+        cSeqsSize < rleMaxLength &&
+        ZSTD_isRLE((BYTE const*)src, srcSize)) {
+        /* We don't want to emit our first block as a RLE even if it qualifies because
+        * doing so will cause the decoder (cli only) to throw a "should consume all input error."
+        * This is only an issue for zstd <= v1.4.3
+        */
+        cSeqsSize = 1;
+    }
+
+    if (zc->seqCollector.collectSequences) {
+        ZSTD_copyBlockSequences(zc);
+        ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
+        return 0;
+    }
+
+    if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
+        zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
+
+    if (cSeqsSize == 0) {
+        cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, srcSize, lastBlock);
+        FORWARD_IF_ERROR(cSize, "Nocompress block failed");
+        DEBUGLOG(4, "Writing out nocompress block, size: %zu", cSize);
+        *dRep = dRepOriginal; /* reset simulated decompression repcode history */
+    } else if (cSeqsSize == 1) {
+        cSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, srcSize, lastBlock);
+        FORWARD_IF_ERROR(cSize, "RLE compress block failed");
+        DEBUGLOG(4, "Writing out RLE block, size: %zu", cSize);
+        *dRep = dRepOriginal; /* reset simulated decompression repcode history */
+    } else {
+        ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
+        writeBlockHeader(op, cSeqsSize, srcSize, lastBlock);
+        cSize = ZSTD_blockHeaderSize + cSeqsSize;
+        DEBUGLOG(4, "Writing out compressed block, size: %zu", cSize);
+    }
+    return cSize;
+}
+
+/* Struct to keep track of where we are in our recursive calls. */
+typedef struct {
+    U32* splitLocations;    /* Array of split indices */
+    size_t idx;             /* The current index within splitLocations being worked on */
+} seqStoreSplits;
+
+#define MIN_SEQUENCES_BLOCK_SPLITTING 300
+#define MAX_NB_SPLITS 196
+
+/* Helper function to perform the recursive search for block splits.
+ * Estimates the cost of seqStore prior to split, and estimates the cost of splitting the sequences in half.
+ * If advantageous to split, then we recurse down the two sub-blocks. If not, or if an error occurred in estimation, then
+ * we do not recurse.
+ *
+ * Note: The recursion depth is capped by a heuristic minimum number of sequences, defined by MIN_SEQUENCES_BLOCK_SPLITTING.
+ * In theory, this means the absolute largest recursion depth is 10 == log2(maxNbSeqInBlock/MIN_SEQUENCES_BLOCK_SPLITTING).
+ * In practice, recursion depth usually doesn't go beyond 4.
+ *
+ * Furthermore, the number of splits is capped by MAX_NB_SPLITS. At MAX_NB_SPLITS == 196 with the current existing blockSize
+ * maximum of 128 KB, this value is actually impossible to reach.
+ */
+static void ZSTD_deriveBlockSplitsHelper(seqStoreSplits* splits, size_t startIdx, size_t endIdx,
+                                         const ZSTD_CCtx* zc, const seqStore_t* origSeqStore) {
+    seqStore_t fullSeqStoreChunk;
+    seqStore_t firstHalfSeqStore;
+    seqStore_t secondHalfSeqStore;
+    size_t estimatedOriginalSize;
+    size_t estimatedFirstHalfSize;
+    size_t estimatedSecondHalfSize;
+    size_t midIdx = (startIdx + endIdx)/2;
+
+    if (endIdx - startIdx < MIN_SEQUENCES_BLOCK_SPLITTING || splits->idx >= MAX_NB_SPLITS) {
+        return;
+    }
+    ZSTD_deriveSeqStoreChunk(&fullSeqStoreChunk, origSeqStore, startIdx, endIdx);
+    ZSTD_deriveSeqStoreChunk(&firstHalfSeqStore, origSeqStore, startIdx, midIdx);
+    ZSTD_deriveSeqStoreChunk(&secondHalfSeqStore, origSeqStore, midIdx, endIdx);
+    estimatedOriginalSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(&fullSeqStoreChunk, zc);
+    estimatedFirstHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(&firstHalfSeqStore, zc);
+    estimatedSecondHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(&secondHalfSeqStore, zc);
+    DEBUGLOG(5, "Estimated original block size: %zu -- First half split: %zu -- Second half split: %zu",
+             estimatedOriginalSize, estimatedFirstHalfSize, estimatedSecondHalfSize);
+    if (ZSTD_isError(estimatedOriginalSize) || ZSTD_isError(estimatedFirstHalfSize) || ZSTD_isError(estimatedSecondHalfSize)) {
+        return;
+    }
+    if (estimatedFirstHalfSize + estimatedSecondHalfSize < estimatedOriginalSize) {
+        ZSTD_deriveBlockSplitsHelper(splits, startIdx, midIdx, zc, origSeqStore);
+        splits->splitLocations[splits->idx] = (U32)midIdx;
+        splits->idx++;
+        ZSTD_deriveBlockSplitsHelper(splits, midIdx, endIdx, zc, origSeqStore);
+    }
+}
+
+/* Base recursive function. Populates a table with intra-block partition indices that can improve compression ratio.
+ *
+ * Returns the number of splits made (which equals the size of the partition table - 1).
+ */
+static size_t ZSTD_deriveBlockSplits(ZSTD_CCtx* zc, U32 partitions[], U32 nbSeq) {
+    seqStoreSplits splits = {partitions, 0};
+    if (nbSeq <= 4) {
+        DEBUGLOG(4, "ZSTD_deriveBlockSplits: Too few sequences to split");
+        /* Refuse to try and split anything with less than 4 sequences */
+        return 0;
+    }
+    ZSTD_deriveBlockSplitsHelper(&splits, 0, nbSeq, zc, &zc->seqStore);
+    splits.splitLocations[splits.idx] = nbSeq;
+    DEBUGLOG(5, "ZSTD_deriveBlockSplits: final nb partitions: %zu", splits.idx+1);
+    return splits.idx;
+}
+
+/* ZSTD_compressBlock_splitBlock():
+ * Attempts to split a given block into multiple blocks to improve compression ratio.
+ *
+ * Returns combined size of all blocks (which includes headers), or a ZSTD error code.
+ */
+static size_t ZSTD_compressBlock_splitBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity,
+                                                     const void* src, size_t blockSize, U32 lastBlock, U32 nbSeq) {
+    size_t cSize = 0;
+    const BYTE* ip = (const BYTE*)src;
+    BYTE* op = (BYTE*)dst;
+    U32 partitions[MAX_NB_SPLITS];
+    size_t i = 0;
+    size_t srcBytesTotal = 0;
+    size_t numSplits = ZSTD_deriveBlockSplits(zc, partitions, nbSeq);
+    seqStore_t nextSeqStore;
+    seqStore_t currSeqStore;
+
+    /* If a block is split and some partitions are emitted as RLE/uncompressed, then repcode history
+     * may become invalid. In order to reconcile potentially invalid repcodes, we keep track of two
+     * separate repcode histories that simulate repcode history on compression and decompression side,
+     * and use the histories to determine whether we must replace a particular repcode with its raw offset.
+     *
+     * 1) cRep gets updated for each partition, regardless of whether the block was emitted as uncompressed
+     *    or RLE. This allows us to retrieve the offset value that an invalid repcode references within
+     *    a nocompress/RLE block.
+     * 2) dRep gets updated only for compressed partitions, and when a repcode gets replaced, will use
+     *    the replacement offset value rather than the original repcode to update the repcode history.
+     *    dRep also will be the final repcode history sent to the next block.
+     *
+     * See ZSTD_seqStore_resolveOffCodes() for more details.
+     */
+    repcodes_t dRep;
+    repcodes_t cRep;
+    ZSTD_memcpy(dRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t));
+    ZSTD_memcpy(cRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t));
+
+    DEBUGLOG(4, "ZSTD_compressBlock_splitBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
+                (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit,
+                (unsigned)zc->blockState.matchState.nextToUpdate);
+
+    if (numSplits == 0) {
+        size_t cSizeSingleBlock = ZSTD_compressSeqStore_singleBlock(zc, &zc->seqStore,
+                                                                   &dRep, &cRep,
+                                                                    op, dstCapacity,
+                                                                    ip, blockSize,
+                                                                    lastBlock, 0 /* isPartition */);
+        FORWARD_IF_ERROR(cSizeSingleBlock, "Compressing single block from splitBlock_internal() failed!");
+        DEBUGLOG(5, "ZSTD_compressBlock_splitBlock_internal: No splits");
+        assert(cSizeSingleBlock <= ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize);
+        return cSizeSingleBlock;
+    }
+
+    ZSTD_deriveSeqStoreChunk(&currSeqStore, &zc->seqStore, 0, partitions[0]);
+    for (i = 0; i <= numSplits; ++i) {
+        size_t srcBytes;
+        size_t cSizeChunk;
+        U32 const lastPartition = (i == numSplits);
+        U32 lastBlockEntireSrc = 0;
+
+        srcBytes = ZSTD_countSeqStoreLiteralsBytes(&currSeqStore) + ZSTD_countSeqStoreMatchBytes(&currSeqStore);
+        srcBytesTotal += srcBytes;
+        if (lastPartition) {
+            /* This is the final partition, need to account for possible last literals */
+            srcBytes += blockSize - srcBytesTotal;
+            lastBlockEntireSrc = lastBlock;
+        } else {
+            ZSTD_deriveSeqStoreChunk(&nextSeqStore, &zc->seqStore, partitions[i], partitions[i+1]);
+        }
+
+        cSizeChunk = ZSTD_compressSeqStore_singleBlock(zc, &currSeqStore,
+                                                      &dRep, &cRep,
+                                                       op, dstCapacity,
+                                                       ip, srcBytes,
+                                                       lastBlockEntireSrc, 1 /* isPartition */);
+        DEBUGLOG(5, "Estimated size: %zu actual size: %zu", ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(&currSeqStore, zc), cSizeChunk);
+        FORWARD_IF_ERROR(cSizeChunk, "Compressing chunk failed!");
+
+        ip += srcBytes;
+        op += cSizeChunk;
+        dstCapacity -= cSizeChunk;
+        cSize += cSizeChunk;
+        currSeqStore = nextSeqStore;
+        assert(cSizeChunk <= ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize);
+    }
+    /* cRep and dRep may have diverged during the compression. If so, we use the dRep repcodes
+     * for the next block.
+     */
+    ZSTD_memcpy(zc->blockState.prevCBlock->rep, dRep.rep, sizeof(repcodes_t));
+    return cSize;
+}
+
+static size_t ZSTD_compressBlock_splitBlock(ZSTD_CCtx* zc,
+                                        void* dst, size_t dstCapacity,
+                                        const void* src, size_t srcSize, U32 lastBlock) {
+    const BYTE* ip = (const BYTE*)src;
+    BYTE* op = (BYTE*)dst;
+    U32 nbSeq;
+    size_t cSize;
+    DEBUGLOG(4, "ZSTD_compressBlock_splitBlock");
+
+    {   const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
+        FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed");
+        if (bss == ZSTDbss_noCompress) {
+            if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
+                zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
+            cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, srcSize, lastBlock);
+            FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
+            DEBUGLOG(4, "ZSTD_compressBlock_splitBlock: Nocompress block");
+            return cSize;
+        }
+        nbSeq = (U32)(zc->seqStore.sequences - zc->seqStore.sequencesStart);
+    }
+
+    assert(zc->appliedParams.splitBlocks == 1);
+    cSize = ZSTD_compressBlock_splitBlock_internal(zc, dst, dstCapacity, src, srcSize, lastBlock, nbSeq);
+    FORWARD_IF_ERROR(cSize, "Splitting blocks failed!");
+    return cSize;
 }
 
 static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
@@ -2434,18 +3733,25 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
 
     if (zc->seqCollector.collectSequences) {
         ZSTD_copyBlockSequences(zc);
+        ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
         return 0;
     }
 
     /* encode sequences and literals */
-    cSize = ZSTD_compressSequences(&zc->seqStore,
+    cSize = ZSTD_entropyCompressSeqStore(&zc->seqStore,
             &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
             &zc->appliedParams,
             dst, dstCapacity,
             srcSize,
-            zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
+            zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
             zc->bmi2);
 
+    if (zc->seqCollector.collectSequences) {
+        ZSTD_copyBlockSequences(zc);
+        return 0;
+    }
+
+
     if (frame &&
         /* We don't want to emit our first block as a RLE even if it qualifies because
          * doing so will cause the decoder (cli only) to throw a "should consume all input error."
@@ -2461,7 +3767,7 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
 
 out:
     if (!ZSTD_isError(cSize) && cSize > 1) {
-        ZSTD_confirmRepcodesAndEntropyTables(zc);
+        ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
     }
     /* We check that dictionaries have offset codes available for the first
      * block. After the first block, the offcode table might not have large
@@ -2514,7 +3820,7 @@ static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc,
                 size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy);
                 FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed");
                 if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) {
-                    ZSTD_confirmRepcodesAndEntropyTables(zc);
+                    ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
                     return cSize;
                 }
             }
@@ -2554,9 +3860,9 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms,
                                          void const* ip,
                                          void const* iend)
 {
-    if (ZSTD_window_needOverflowCorrection(ms->window, iend)) {
-        U32 const maxDist = (U32)1 << params->cParams.windowLog;
-        U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy);
+    U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy);
+    U32 const maxDist = (U32)1 << params->cParams.windowLog;
+    if (ZSTD_window_needOverflowCorrection(ms->window, cycleLog, maxDist, ms->loadedDictEnd, ip, iend)) {
         U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip);
         ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
         ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
@@ -2579,7 +3885,7 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms,
 *   Frame is supposed already started (header already produced)
 *   @return : compressed size, or an error code
 */
-static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
+static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx,
                                      void* dst, size_t dstCapacity,
                                const void* src, size_t srcSize,
                                      U32 lastFrameChunk)
@@ -2593,7 +3899,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
 
     assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX);
 
-    DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize);
+    DEBUGLOG(4, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize);
     if (cctx->appliedParams.fParams.checksumFlag && srcSize)
         XXH64_update(&cctx->xxhState, src, srcSize);
 
@@ -2619,6 +3925,10 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
                 FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed");
                 assert(cSize > 0);
                 assert(cSize <= blockSize + ZSTD_blockHeaderSize);
+            } else if (ZSTD_blockSplitterEnabled(&cctx->appliedParams)) {
+                cSize = ZSTD_compressBlock_splitBlock(cctx, op, dstCapacity, ip, blockSize, lastBlock);
+                FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_splitBlock failed");
+                assert(cSize > 0 || cctx->seqCollector.collectSequences == 1);
             } else {
                 cSize = ZSTD_compressBlock_internal(cctx,
                                         op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
@@ -2673,7 +3983,6 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
                     "dst buf is too small to fit worst-case frame header size.");
     DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
                 !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode);
-
     if (params->format == ZSTD_f_zstd1) {
         MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
         pos = 4;
@@ -2699,6 +4008,26 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
     return pos;
 }
 
+/* ZSTD_writeSkippableFrame_advanced() :
+ * Writes out a skippable frame with the specified magic number variant (16 are supported),
+ * from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15, and the desired source data.
+ *
+ * Returns the total number of bytes written, or a ZSTD error code.
+ */
+size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity,
+                                const void* src, size_t srcSize, unsigned magicVariant) {
+    BYTE* op = (BYTE*)dst;
+    RETURN_ERROR_IF(dstCapacity < srcSize + ZSTD_SKIPPABLEHEADERSIZE /* Skippable frame overhead */,
+                    dstSize_tooSmall, "Not enough room for skippable frame");
+    RETURN_ERROR_IF(srcSize > (unsigned)0xFFFFFFFF, srcSize_wrong, "Src size too large for skippable frame");
+    RETURN_ERROR_IF(magicVariant > 15, parameter_outOfBound, "Skippable frame magic number variant not supported");
+
+    MEM_writeLE32(op, (U32)(ZSTD_MAGIC_SKIPPABLE_START + magicVariant));
+    MEM_writeLE32(op+4, (U32)srcSize);
+    ZSTD_memcpy(op+8, src, srcSize);
+    return srcSize + ZSTD_SKIPPABLEHEADERSIZE;
+}
+
 /* ZSTD_writeLastEmptyBlock() :
  * output an empty Block with end-of-frame mark to complete a frame
  * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
@@ -2725,6 +4054,7 @@ size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSe
     cctx->externSeqStore.size = nbSeq;
     cctx->externSeqStore.capacity = nbSeq;
     cctx->externSeqStore.pos = 0;
+    cctx->externSeqStore.posInSequence = 0;
     return 0;
 }
 
@@ -2754,11 +4084,12 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
 
     if (!srcSize) return fhSize;  /* do not generate an empty block if no input */
 
-    if (!ZSTD_window_update(&ms->window, src, srcSize)) {
+    if (!ZSTD_window_update(&ms->window, src, srcSize, ms->forceNonContiguous)) {
+        ms->forceNonContiguous = 0;
         ms->nextToUpdate = ms->window.dictLimit;
     }
     if (cctx->appliedParams.ldmParams.enableLdm) {
-        ZSTD_window_update(&cctx->ldmState.window, src, srcSize);
+        ZSTD_window_update(&cctx->ldmState.window, src, srcSize, /* forceNonContiguous */ 0);
     }
 
     if (!frame) {
@@ -2826,59 +4157,86 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
 {
     const BYTE* ip = (const BYTE*) src;
     const BYTE* const iend = ip + srcSize;
-
-    ZSTD_window_update(&ms->window, src, srcSize);
-    ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base);
-
-    if (params->ldmParams.enableLdm && ls != NULL) {
-        ZSTD_window_update(&ls->window, src, srcSize);
-        ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base);
-    }
+    int const loadLdmDict = params->ldmParams.enableLdm && ls != NULL;
 
     /* Assert that we the ms params match the params we're being given */
     ZSTD_assertEqualCParams(params->cParams, ms->cParams);
 
-    if (srcSize <= HASH_READ_SIZE) return 0;
+    if (srcSize > ZSTD_CHUNKSIZE_MAX) {
+        /* Allow the dictionary to set indices up to exactly ZSTD_CURRENT_MAX.
+         * Dictionaries right at the edge will immediately trigger overflow
+         * correction, but I don't want to insert extra constraints here.
+         */
+        U32 const maxDictSize = ZSTD_CURRENT_MAX - 1;
+        /* We must have cleared our windows when our source is this large. */
+        assert(ZSTD_window_isEmpty(ms->window));
+        if (loadLdmDict)
+            assert(ZSTD_window_isEmpty(ls->window));
+        /* If the dictionary is too large, only load the suffix of the dictionary. */
+        if (srcSize > maxDictSize) {
+            ip = iend - maxDictSize;
+            src = ip;
+            srcSize = maxDictSize;
+        }
+    }
 
-    while (iend - ip > HASH_READ_SIZE) {
-        size_t const remaining = (size_t)(iend - ip);
-        size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX);
-        const BYTE* const ichunk = ip + chunk;
+    DEBUGLOG(4, "ZSTD_loadDictionaryContent(): useRowMatchFinder=%d", (int)params->useRowMatchFinder);
+    ZSTD_window_update(&ms->window, src, srcSize, /* forceNonContiguous */ 0);
+    ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base);
+    ms->forceNonContiguous = params->deterministicRefPrefix;
 
-        ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk);
+    if (loadLdmDict) {
+        ZSTD_window_update(&ls->window, src, srcSize, /* forceNonContiguous */ 0);
+        ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base);
+    }
 
-        if (params->ldmParams.enableLdm && ls != NULL)
-            ZSTD_ldm_fillHashTable(ls, (const BYTE*)src, (const BYTE*)src + srcSize, &params->ldmParams);
+    if (srcSize <= HASH_READ_SIZE) return 0;
 
-        switch(params->cParams.strategy)
-        {
-        case ZSTD_fast:
-            ZSTD_fillHashTable(ms, ichunk, dtlm);
-            break;
-        case ZSTD_dfast:
-            ZSTD_fillDoubleHashTable(ms, ichunk, dtlm);
-            break;
+    ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, iend);
 
-        case ZSTD_greedy:
-        case ZSTD_lazy:
-        case ZSTD_lazy2:
-            if (chunk >= HASH_READ_SIZE)
-                ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE);
-            break;
+    if (loadLdmDict)
+        ZSTD_ldm_fillHashTable(ls, ip, iend, &params->ldmParams);
 
-        case ZSTD_btlazy2:   /* we want the dictionary table fully sorted */
-        case ZSTD_btopt:
-        case ZSTD_btultra:
-        case ZSTD_btultra2:
-            if (chunk >= HASH_READ_SIZE)
-                ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk);
-            break;
+    switch(params->cParams.strategy)
+    {
+    case ZSTD_fast:
+        ZSTD_fillHashTable(ms, iend, dtlm);
+        break;
+    case ZSTD_dfast:
+        ZSTD_fillDoubleHashTable(ms, iend, dtlm);
+        break;
 
-        default:
-            assert(0);  /* not possible : not a valid strategy id */
+    case ZSTD_greedy:
+    case ZSTD_lazy:
+    case ZSTD_lazy2:
+        assert(srcSize >= HASH_READ_SIZE);
+        if (ms->dedicatedDictSearch) {
+            assert(ms->chainTable != NULL);
+            ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, iend-HASH_READ_SIZE);
+        } else {
+            assert(params->useRowMatchFinder != ZSTD_urm_auto);
+            if (params->useRowMatchFinder == ZSTD_urm_enableRowMatchFinder) {
+                size_t const tagTableSize = ((size_t)1 << params->cParams.hashLog) * sizeof(U16);
+                ZSTD_memset(ms->tagTable, 0, tagTableSize);
+                ZSTD_row_update(ms, iend-HASH_READ_SIZE);
+                DEBUGLOG(4, "Using row-based hash table for lazy dict");
+            } else {
+                ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE);
+                DEBUGLOG(4, "Using chain-based hash table for lazy dict");
+            }
         }
+        break;
+
+    case ZSTD_btlazy2:   /* we want the dictionary table fully sorted */
+    case ZSTD_btopt:
+    case ZSTD_btultra:
+    case ZSTD_btultra2:
+        assert(srcSize >= HASH_READ_SIZE);
+        ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend);
+        break;
 
-        ip = ichunk;
+    default:
+        assert(0);  /* not possible : not a valid strategy id */
     }
 
     ms->nextToUpdate = (U32)(iend - ms->window.base);
@@ -2887,22 +4245,28 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
 
 
 /* Dictionaries that assign zero probability to symbols that show up causes problems
-   when FSE encoding.  Refuse dictionaries that assign zero probability to symbols
-   that we may encounter during compression.
-   NOTE: This behavior is not standard and could be improved in the future. */
-static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
+ * when FSE encoding. Mark dictionaries with zero probability symbols as FSE_repeat_check
+ * and only dictionaries with 100% valid symbols can be assumed valid.
+ */
+static FSE_repeat ZSTD_dictNCountRepeat(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue)
+{
     U32 s;
-    RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted, "dict fse tables don't have all symbols");
+    if (dictMaxSymbolValue < maxSymbolValue) {
+        return FSE_repeat_check;
+    }
     for (s = 0; s <= maxSymbolValue; ++s) {
-        RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted, "dict fse tables don't have all symbols");
+        if (normalizedCounter[s] == 0) {
+            return FSE_repeat_check;
+        }
     }
-    return 0;
+    return FSE_repeat_valid;
 }
 
 size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
-                         short* offcodeNCount, unsigned* offcodeMaxValue,
                          const void* const dict, size_t dictSize)
 {
+    short offcodeNCount[MaxOff+1];
+    unsigned offcodeMaxValue = MaxOff;
     const BYTE* dictPtr = (const BYTE*)dict;    /* skip magic num and dict ID */
     const BYTE* const dictEnd = dictPtr + dictSize;
     dictPtr += 8;
@@ -2924,16 +4288,16 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
     }
 
     {   unsigned offcodeLog;
-        size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
+        size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
         RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
         RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
-        /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
         /* fill all offset symbols to avoid garbage at end of table */
         RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
                 bs->entropy.fse.offcodeCTable,
                 offcodeNCount, MaxOff, offcodeLog,
                 workspace, HUF_WORKSPACE_SIZE)),
             dictionary_corrupted, "");
+        /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
         dictPtr += offcodeHeaderSize;
     }
 
@@ -2942,13 +4306,12 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
         size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
         RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
         RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");
-        /* Every match length code must have non-zero probability */
-        FORWARD_IF_ERROR( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML), "");
         RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
                 bs->entropy.fse.matchlengthCTable,
                 matchlengthNCount, matchlengthMaxValue, matchlengthLog,
                 workspace, HUF_WORKSPACE_SIZE)),
             dictionary_corrupted, "");
+        bs->entropy.fse.matchlength_repeatMode = ZSTD_dictNCountRepeat(matchlengthNCount, matchlengthMaxValue, MaxML);
         dictPtr += matchlengthHeaderSize;
     }
 
@@ -2957,13 +4320,12 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
         size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
         RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
         RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");
-        /* Every literal length code must have non-zero probability */
-        FORWARD_IF_ERROR( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL), "");
         RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
                 bs->entropy.fse.litlengthCTable,
                 litlengthNCount, litlengthMaxValue, litlengthLog,
                 workspace, HUF_WORKSPACE_SIZE)),
             dictionary_corrupted, "");
+        bs->entropy.fse.litlength_repeatMode = ZSTD_dictNCountRepeat(litlengthNCount, litlengthMaxValue, MaxLL);
         dictPtr += litlengthHeaderSize;
     }
 
@@ -2973,12 +4335,28 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
     bs->rep[2] = MEM_readLE32(dictPtr+8);
     dictPtr += 12;
 
+    {   size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
+        U32 offcodeMax = MaxOff;
+        if (dictContentSize <= ((U32)-1) - 128 KB) {
+            U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
+            offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
+        }
+        /* All offset values <= dictContentSize + 128 KB must be representable for a valid table */
+        bs->entropy.fse.offcode_repeatMode = ZSTD_dictNCountRepeat(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff));
+
+        /* All repCodes must be <= dictContentSize and != 0 */
+        {   U32 u;
+            for (u=0; u<3; u++) {
+                RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, "");
+                RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, "");
+    }   }   }
+
     return dictPtr - (const BYTE*)dict;
 }
 
 /* Dictionary format :
  * See :
- * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
+ * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#dictionary-format
  */
 /*! ZSTD_loadZstdDictionary() :
  * @return : dictID, or an error code
@@ -2995,42 +4373,23 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
 {
     const BYTE* dictPtr = (const BYTE*)dict;
     const BYTE* const dictEnd = dictPtr + dictSize;
-    short offcodeNCount[MaxOff+1];
-    unsigned offcodeMaxValue = MaxOff;
     size_t dictID;
     size_t eSize;
-
     ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
     assert(dictSize >= 8);
     assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
 
     dictID = params->fParams.noDictIDFlag ? 0 :  MEM_readLE32(dictPtr + 4 /* skip magic number */ );
-    eSize = ZSTD_loadCEntropy(bs, workspace, offcodeNCount, &offcodeMaxValue, dict, dictSize);
+    eSize = ZSTD_loadCEntropy(bs, workspace, dict, dictSize);
     FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed");
     dictPtr += eSize;
 
-    {   size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
-        U32 offcodeMax = MaxOff;
-        if (dictContentSize <= ((U32)-1) - 128 KB) {
-            U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
-            offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
-        }
-        /* All offset values <= dictContentSize + 128 KB must be representable */
-        FORWARD_IF_ERROR(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)), "");
-        /* All repCodes must be <= dictContentSize and != 0*/
-        {   U32 u;
-            for (u=0; u<3; u++) {
-                RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, "");
-                RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, "");
-        }   }
-
-        bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid;
-        bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid;
-        bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid;
+    {
+        size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
         FORWARD_IF_ERROR(ZSTD_loadDictionaryContent(
             ms, NULL, ws, params, dictPtr, dictContentSize, dtlm), "");
-        return dictID;
     }
+    return dictID;
 }
 
 /** ZSTD_compress_insertDictionary() :
@@ -3074,7 +4433,7 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs,
 }
 
 #define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB)
-#define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6)
+#define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6ULL)
 
 /*! ZSTD_compressBegin_internal() :
  * @return : 0, or an error code */
@@ -3086,6 +4445,10 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
                                     const ZSTD_CCtx_params* params, U64 pledgedSrcSize,
                                     ZSTD_buffered_policy_e zbuff)
 {
+    size_t const dictContentSize = cdict ? cdict->dictContentSize : dictSize;
+#if ZSTD_TRACE
+    cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0;
+#endif
     DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog);
     /* params are supposed to be fully validated at this point */
     assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
@@ -3100,13 +4463,14 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
         return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff);
     }
 
-    FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, *params, pledgedSrcSize,
+    FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
+                                     dictContentSize,
                                      ZSTDcrp_makeClean, zbuff) , "");
     {   size_t const dictID = cdict ?
                 ZSTD_compress_insertDictionary(
                         cctx->blockState.prevCBlock, &cctx->blockState.matchState,
                         &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent,
-                        cdict->dictContentSize, dictContentType, dtlm,
+                        cdict->dictContentSize, cdict->dictContentType, dtlm,
                         cctx->entropyWorkspace)
               : ZSTD_compress_insertDictionary(
                         cctx->blockState.prevCBlock, &cctx->blockState.matchState,
@@ -3115,6 +4479,7 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
         FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed");
         assert(dictID <= UINT_MAX);
         cctx->dictID = (U32)dictID;
+        cctx->dictContentSize = dictContentSize;
     }
     return 0;
 }
@@ -3143,8 +4508,8 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
                              const void* dict, size_t dictSize,
                                    ZSTD_parameters params, unsigned long long pledgedSrcSize)
 {
-    ZSTD_CCtx_params const cctxParams =
-            ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
+    ZSTD_CCtx_params cctxParams;
+    ZSTD_CCtxParams_init_internal(&cctxParams, &params, ZSTD_NO_CLEVEL);
     return ZSTD_compressBegin_advanced_internal(cctx,
                                             dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast,
                                             NULL /*cdict*/,
@@ -3153,9 +4518,11 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
 
 size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
 {
-    ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
-    ZSTD_CCtx_params const cctxParams =
-            ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
+    ZSTD_CCtx_params cctxParams;
+    {
+        ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict);
+        ZSTD_CCtxParams_init_internal(&cctxParams, &params, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel);
+    }
     DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize);
     return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
                                        &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
@@ -3209,6 +4576,30 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
     return op-ostart;
 }
 
+void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize)
+{
+#if ZSTD_TRACE
+    if (cctx->traceCtx && ZSTD_trace_compress_end != NULL) {
+        int const streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0 || cctx->appliedParams.nbWorkers > 0;
+        ZSTD_Trace trace;
+        ZSTD_memset(&trace, 0, sizeof(trace));
+        trace.version = ZSTD_VERSION_NUMBER;
+        trace.streaming = streaming;
+        trace.dictionaryID = cctx->dictID;
+        trace.dictionarySize = cctx->dictContentSize;
+        trace.uncompressedSize = cctx->consumedSrcSize;
+        trace.compressedSize = cctx->producedCSize + extraCSize;
+        trace.params = &cctx->appliedParams;
+        trace.cctx = cctx;
+        ZSTD_trace_compress_end(cctx->traceCtx, &trace);
+    }
+    cctx->traceCtx = 0;
+#else
+    (void)cctx;
+    (void)extraCSize;
+#endif
+}
+
 size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
                          void* dst, size_t dstCapacity,
                    const void* src, size_t srcSize)
@@ -3231,26 +4622,10 @@ size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
             (unsigned)cctx->pledgedSrcSizePlusOne-1,
             (unsigned)cctx->consumedSrcSize);
     }
+    ZSTD_CCtx_trace(cctx, endResult);
     return cSize + endResult;
 }
 
-
-static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
-                                      void* dst, size_t dstCapacity,
-                                const void* src, size_t srcSize,
-                                const void* dict,size_t dictSize,
-                                const ZSTD_parameters* params)
-{
-    ZSTD_CCtx_params const cctxParams =
-            ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params);
-    DEBUGLOG(4, "ZSTD_compress_internal");
-    return ZSTD_compress_advanced_internal(cctx,
-                                           dst, dstCapacity,
-                                           src, srcSize,
-                                           dict, dictSize,
-                                           &cctxParams);
-}
-
 size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
                                void* dst, size_t dstCapacity,
                          const void* src, size_t srcSize,
@@ -3259,11 +4634,12 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
 {
     DEBUGLOG(4, "ZSTD_compress_advanced");
     FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), "");
-    return ZSTD_compress_internal(cctx,
-                                  dst, dstCapacity,
-                                  src, srcSize,
-                                  dict, dictSize,
-                                  &params);
+    ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, &params, ZSTD_NO_CLEVEL);
+    return ZSTD_compress_advanced_internal(cctx,
+                                           dst, dstCapacity,
+                                           src, srcSize,
+                                           dict, dictSize,
+                                           &cctx->simpleApiParams);
 }
 
 /* Internal */
@@ -3287,11 +4663,13 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx,
                          const void* dict, size_t dictSize,
                                int compressionLevel)
 {
-    ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0);
-    ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
+    {
+        ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict);
+        assert(params.fParams.contentSizeFlag == 1);
+        ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, &params, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT: compressionLevel);
+    }
     DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize);
-    assert(params.fParams.contentSizeFlag == 1);
-    return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams);
+    return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctx->simpleApiParams);
 }
 
 size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
@@ -3309,10 +4687,17 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity,
                      int compressionLevel)
 {
     size_t result;
+#if ZSTD_COMPRESS_HEAPMODE
+    ZSTD_CCtx* cctx = ZSTD_createCCtx();
+    RETURN_ERROR_IF(!cctx, memory_allocation, "ZSTD_createCCtx failed");
+    result = ZSTD_compressCCtx(cctx, dst, dstCapacity, src, srcSize, compressionLevel);
+    ZSTD_freeCCtx(cctx);
+#else
     ZSTD_CCtx ctxBody;
     ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem);
     result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
     ZSTD_freeCCtxContent(&ctxBody);   /* can't free ctxBody itself, as it's on stack; free only heap content */
+#endif
     return result;
 }
 
@@ -3328,14 +4713,17 @@ size_t ZSTD_estimateCDictSize_advanced(
     DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict));
     return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
          + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
-         + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0)
+         /* enableDedicatedDictSearch == 1 ensures that CDict estimation will not be too small
+          * in case we are using DDS with row-hash. */
+         + ZSTD_sizeof_matchState(&cParams, ZSTD_resolveRowMatchFinderMode(ZSTD_urm_auto, &cParams),
+                                  /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0)
          + (dictLoadMethod == ZSTD_dlm_byRef ? 0
             : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *))));
 }
 
 size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
 {
-    ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
+    ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
     return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
 }
 
@@ -3353,20 +4741,22 @@ static size_t ZSTD_initCDict_internal(
               const void* dictBuffer, size_t dictSize,
                     ZSTD_dictLoadMethod_e dictLoadMethod,
                     ZSTD_dictContentType_e dictContentType,
-                    ZSTD_compressionParameters cParams)
+                    ZSTD_CCtx_params params)
 {
     DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType);
-    assert(!ZSTD_checkCParams(cParams));
-    cdict->matchState.cParams = cParams;
+    assert(!ZSTD_checkCParams(params.cParams));
+    cdict->matchState.cParams = params.cParams;
+    cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch;
     if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
         cdict->dictContent = dictBuffer;
     } else {
          void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*)));
         RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!");
         cdict->dictContent = internalBuffer;
-        memcpy(internalBuffer, dictBuffer, dictSize);
+        ZSTD_memcpy(internalBuffer, dictBuffer, dictSize);
     }
     cdict->dictContentSize = dictSize;
+    cdict->dictContentType = dictContentType;
 
     cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE);
 
@@ -3376,18 +4766,16 @@ static size_t ZSTD_initCDict_internal(
     FORWARD_IF_ERROR(ZSTD_reset_matchState(
         &cdict->matchState,
         &cdict->workspace,
-        &cParams,
+        &params.cParams,
+        params.useRowMatchFinder,
         ZSTDcrp_makeClean,
         ZSTDirp_reset,
         ZSTD_resetTarget_CDict), "");
     /* (Maybe) load the dictionary
      * Skips loading the dictionary if it is < 8 bytes.
      */
-    {   ZSTD_CCtx_params params;
-        memset(&params, 0, sizeof(params));
-        params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
+    {   params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
         params.fParams.contentSizeFlag = 1;
-        params.cParams = cParams;
         {   size_t const dictID = ZSTD_compress_insertDictionary(
                     &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace,
                     &params, cdict->dictContent, cdict->dictContentSize,
@@ -3401,66 +4789,129 @@ static size_t ZSTD_initCDict_internal(
     return 0;
 }
 
-ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
+static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize,
                                       ZSTD_dictLoadMethod_e dictLoadMethod,
-                                      ZSTD_dictContentType_e dictContentType,
-                                      ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
+                                      ZSTD_compressionParameters cParams,
+                                      ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
+                                      U32 enableDedicatedDictSearch,
+                                      ZSTD_customMem customMem)
 {
-    DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType);
-    if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+    if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
 
     {   size_t const workspaceSize =
             ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) +
             ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) +
-            ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) +
+            ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, enableDedicatedDictSearch, /* forCCtx */ 0) +
             (dictLoadMethod == ZSTD_dlm_byRef ? 0
              : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))));
-        void* const workspace = ZSTD_malloc(workspaceSize, customMem);
+        void* const workspace = ZSTD_customMalloc(workspaceSize, customMem);
         ZSTD_cwksp ws;
         ZSTD_CDict* cdict;
 
         if (!workspace) {
-            ZSTD_free(workspace, customMem);
+            ZSTD_customFree(workspace, customMem);
             return NULL;
         }
 
-        ZSTD_cwksp_init(&ws, workspace, workspaceSize);
+        ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_dynamic_alloc);
 
         cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
         assert(cdict != NULL);
         ZSTD_cwksp_move(&cdict->workspace, &ws);
         cdict->customMem = customMem;
-        cdict->compressionLevel = 0; /* signals advanced API usage */
+        cdict->compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */
+        cdict->useRowMatchFinder = useRowMatchFinder;
+        return cdict;
+    }
+}
+
+ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
+                                      ZSTD_dictLoadMethod_e dictLoadMethod,
+                                      ZSTD_dictContentType_e dictContentType,
+                                      ZSTD_compressionParameters cParams,
+                                      ZSTD_customMem customMem)
+{
+    ZSTD_CCtx_params cctxParams;
+    ZSTD_memset(&cctxParams, 0, sizeof(cctxParams));
+    ZSTD_CCtxParams_init(&cctxParams, 0);
+    cctxParams.cParams = cParams;
+    cctxParams.customMem = customMem;
+    return ZSTD_createCDict_advanced2(
+        dictBuffer, dictSize,
+        dictLoadMethod, dictContentType,
+        &cctxParams, customMem);
+}
+
+ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced2(
+        const void* dict, size_t dictSize,
+        ZSTD_dictLoadMethod_e dictLoadMethod,
+        ZSTD_dictContentType_e dictContentType,
+        const ZSTD_CCtx_params* originalCctxParams,
+        ZSTD_customMem customMem)
+{
+    ZSTD_CCtx_params cctxParams = *originalCctxParams;
+    ZSTD_compressionParameters cParams;
+    ZSTD_CDict* cdict;
+
+    DEBUGLOG(3, "ZSTD_createCDict_advanced2, mode %u", (unsigned)dictContentType);
+    if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+
+    if (cctxParams.enableDedicatedDictSearch) {
+        cParams = ZSTD_dedicatedDictSearch_getCParams(
+            cctxParams.compressionLevel, dictSize);
+        ZSTD_overrideCParams(&cParams, &cctxParams.cParams);
+    } else {
+        cParams = ZSTD_getCParamsFromCCtxParams(
+            &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
+    }
 
-        if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
-                                        dictBuffer, dictSize,
-                                        dictLoadMethod, dictContentType,
-                                        cParams) )) {
-            ZSTD_freeCDict(cdict);
-            return NULL;
-        }
+    if (!ZSTD_dedicatedDictSearch_isSupported(&cParams)) {
+        /* Fall back to non-DDSS params */
+        cctxParams.enableDedicatedDictSearch = 0;
+        cParams = ZSTD_getCParamsFromCCtxParams(
+            &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
+    }
 
-        return cdict;
+    DEBUGLOG(3, "ZSTD_createCDict_advanced2: DDS: %u", cctxParams.enableDedicatedDictSearch);
+    cctxParams.cParams = cParams;
+    cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams);
+
+    cdict = ZSTD_createCDict_advanced_internal(dictSize,
+                        dictLoadMethod, cctxParams.cParams,
+                        cctxParams.useRowMatchFinder, cctxParams.enableDedicatedDictSearch,
+                        customMem);
+
+    if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
+                                    dict, dictSize,
+                                    dictLoadMethod, dictContentType,
+                                    cctxParams) )) {
+        ZSTD_freeCDict(cdict);
+        return NULL;
     }
+
+    return cdict;
 }
 
 ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
 {
-    ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
-    ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dict, dictSize,
+    ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
+    ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize,
                                                   ZSTD_dlm_byCopy, ZSTD_dct_auto,
                                                   cParams, ZSTD_defaultCMem);
     if (cdict)
-        cdict->compressionLevel = compressionLevel == 0 ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
+        cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
     return cdict;
 }
 
 ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
 {
-    ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
-    return ZSTD_createCDict_advanced(dict, dictSize,
+    ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
+    ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize,
                                      ZSTD_dlm_byRef, ZSTD_dct_auto,
                                      cParams, ZSTD_defaultCMem);
+    if (cdict)
+        cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
+    return cdict;
 }
 
 size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
@@ -3470,7 +4921,7 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
         int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict);
         ZSTD_cwksp_free(&cdict->workspace, cMem);
         if (!cdictInWorkspace) {
-            ZSTD_free(cdict, cMem);
+            ZSTD_customFree(cdict, cMem);
         }
         return 0;
     }
@@ -3496,19 +4947,22 @@ const ZSTD_CDict* ZSTD_initStaticCDict(
                                  ZSTD_dictContentType_e dictContentType,
                                  ZSTD_compressionParameters cParams)
 {
-    size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
+    ZSTD_useRowMatchFinderMode_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(ZSTD_urm_auto, &cParams);
+    /* enableDedicatedDictSearch == 1 ensures matchstate is not too small in case this CDict will be used for DDS + row hash */
+    size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0);
     size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
                             + (dictLoadMethod == ZSTD_dlm_byRef ? 0
                                : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))))
                             + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
                             + matchStateSize;
     ZSTD_CDict* cdict;
+    ZSTD_CCtx_params params;
 
     if ((size_t)workspace & 7) return NULL;  /* 8-aligned */
 
     {
         ZSTD_cwksp ws;
-        ZSTD_cwksp_init(&ws, workspace, workspaceSize);
+        ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc);
         cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
         if (cdict == NULL) return NULL;
         ZSTD_cwksp_move(&cdict->workspace, &ws);
@@ -3518,10 +4972,15 @@ const ZSTD_CDict* ZSTD_initStaticCDict(
         (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize));
     if (workspaceSize < neededSize) return NULL;
 
+    ZSTD_CCtxParams_init(&params, 0);
+    params.cParams = cParams;
+    params.useRowMatchFinder = useRowMatchFinder;
+    cdict->useRowMatchFinder = useRowMatchFinder;
+
     if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
                                               dict, dictSize,
                                               dictLoadMethod, dictContentType,
-                                              cParams) ))
+                                              params) ))
         return NULL;
 
     return cdict;
@@ -3533,61 +4992,98 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict)
     return cdict->matchState.cParams;
 }
 
-/* ZSTD_compressBegin_usingCDict_advanced() :
- * cdict must be != NULL */
-size_t ZSTD_compressBegin_usingCDict_advanced(
+/*! ZSTD_getDictID_fromCDict() :
+ *  Provides the dictID of the dictionary loaded into `cdict`.
+ *  If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
+ *  Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
+unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict)
+{
+    if (cdict==NULL) return 0;
+    return cdict->dictID;
+}
+
+/* ZSTD_compressBegin_usingCDict_internal() :
+ * Implementation of various ZSTD_compressBegin_usingCDict* functions.
+ */
+static size_t ZSTD_compressBegin_usingCDict_internal(
     ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
     ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
 {
-    DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
+    ZSTD_CCtx_params cctxParams;
+    DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_internal");
     RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!");
-    {   ZSTD_CCtx_params params = cctx->requestedParams;
+    /* Initialize the cctxParams from the cdict */
+    {
+        ZSTD_parameters params;
+        params.fParams = fParams;
         params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF
                         || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER
                         || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
-                        || cdict->compressionLevel == 0 )
-                      && (params.attachDictPref != ZSTD_dictForceLoad) ?
+                        || cdict->compressionLevel == 0 ) ?
                 ZSTD_getCParamsFromCDict(cdict)
               : ZSTD_getCParams(cdict->compressionLevel,
                                 pledgedSrcSize,
                                 cdict->dictContentSize);
-        /* Increase window log to fit the entire dictionary and source if the
-         * source size is known. Limit the increase to 19, which is the
-         * window log for compression level 1 with the largest source size.
-         */
-        if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
-            U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19);
-            U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1;
-            params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog);
-        }
-        params.fParams = fParams;
-        return ZSTD_compressBegin_internal(cctx,
-                                           NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast,
-                                           cdict,
-                                           &params, pledgedSrcSize,
-                                           ZSTDb_not_buffered);
+        ZSTD_CCtxParams_init_internal(&cctxParams, &params, cdict->compressionLevel);
     }
+    /* Increase window log to fit the entire dictionary and source if the
+     * source size is known. Limit the increase to 19, which is the
+     * window log for compression level 1 with the largest source size.
+     */
+    if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+        U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19);
+        U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1;
+        cctxParams.cParams.windowLog = MAX(cctxParams.cParams.windowLog, limitedSrcLog);
+    }
+    return ZSTD_compressBegin_internal(cctx,
+                                        NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast,
+                                        cdict,
+                                        &cctxParams, pledgedSrcSize,
+                                        ZSTDb_not_buffered);
+}
+
+
+/* ZSTD_compressBegin_usingCDict_advanced() :
+ * This function is DEPRECATED.
+ * cdict must be != NULL */
+size_t ZSTD_compressBegin_usingCDict_advanced(
+    ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
+    ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
+{
+    return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, pledgedSrcSize);
 }
 
 /* ZSTD_compressBegin_usingCDict() :
- * pledgedSrcSize=0 means "unknown"
- * if pledgedSrcSize>0, it will enable contentSizeFlag */
+ * cdict must be != NULL */
 size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
 {
     ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
-    DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
-    return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
+    return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
 }
 
-size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
+/*! ZSTD_compress_usingCDict_internal():
+ * Implementation of various ZSTD_compress_usingCDict* functions.
+ */
+static size_t ZSTD_compress_usingCDict_internal(ZSTD_CCtx* cctx,
                                 void* dst, size_t dstCapacity,
                                 const void* src, size_t srcSize,
                                 const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
 {
-    FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize), "");   /* will check if cdict != NULL */
+    FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */
     return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
 }
 
+/*! ZSTD_compress_usingCDict_advanced():
+ * This function is DEPRECATED.
+ */
+size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
+                                void* dst, size_t dstCapacity,
+                                const void* src, size_t srcSize,
+                                const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
+{
+    return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
+}
+
 /*! ZSTD_compress_usingCDict() :
  *  Compression using a digested Dictionary.
  *  Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
@@ -3599,7 +5095,7 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
                                 const ZSTD_CDict* cdict)
 {
     ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
-    return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
+    return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
 }
 
 
@@ -3640,32 +5136,12 @@ size_t ZSTD_CStreamOutSize(void)
     return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
 }
 
-static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx,
-                    const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType,
-                    const ZSTD_CDict* const cdict,
-                    ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize)
+static ZSTD_cParamMode_e ZSTD_getCParamMode(ZSTD_CDict const* cdict, ZSTD_CCtx_params const* params, U64 pledgedSrcSize)
 {
-    DEBUGLOG(4, "ZSTD_resetCStream_internal");
-    /* Finalize the compression parameters */
-    params.cParams = ZSTD_getCParamsFromCCtxParams(&params, pledgedSrcSize, dictSize);
-    /* params are supposed to be fully validated at this point */
-    assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
-    assert(!((dict) && (cdict)));  /* either dict or cdict, not both */
-
-    FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx,
-                                         dict, dictSize, dictContentType, ZSTD_dtlm_fast,
-                                         cdict,
-                                         &params, pledgedSrcSize,
-                                         ZSTDb_buffered) , "");
-
-    cctx->inToCompress = 0;
-    cctx->inBuffPos = 0;
-    cctx->inBuffTarget = cctx->blockSize
-                      + (cctx->blockSize == pledgedSrcSize);   /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */
-    cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
-    cctx->streamStage = zcss_load;
-    cctx->frameEnded = 0;
-    return 0;   /* ready to go */
+    if (cdict != NULL && ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize))
+        return ZSTD_cpm_attachDict;
+    else
+        return ZSTD_cpm_noAttachDict;
 }
 
 /* ZSTD_resetCStream():
@@ -3749,7 +5225,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
     FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
     FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
     FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
-    zcs->requestedParams = ZSTD_assignParamsToCCtxParams(&zcs->requestedParams, &params);
+    ZSTD_CCtxParams_setZstdParams(&zcs->requestedParams, &params);
     FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
     return 0;
 }
@@ -3815,12 +5291,17 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
 
     /* check expectations */
     DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode);
-    assert(zcs->inBuff != NULL);
-    assert(zcs->inBuffSize > 0);
-    assert(zcs->outBuff !=  NULL);
-    assert(zcs->outBuffSize > 0);
+    if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) {
+        assert(zcs->inBuff != NULL);
+        assert(zcs->inBuffSize > 0);
+    }
+    if (zcs->appliedParams.outBufferMode == ZSTD_bm_buffered) {
+        assert(zcs->outBuff !=  NULL);
+        assert(zcs->outBuffSize > 0);
+    }
     assert(output->pos <= output->size);
     assert(input->pos <= input->size);
+    assert((U32)flushMode <= (U32)ZSTD_e_end);
 
     while (someMoreWork) {
         switch(zcs->streamStage)
@@ -3830,7 +5311,8 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
 
         case zcss_load:
             if ( (flushMode == ZSTD_e_end)
-              && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip))  /* enough dstCapacity */
+              && ( (size_t)(oend-op) >= ZSTD_compressBound(iend-ip)     /* Enough output space */
+                || zcs->appliedParams.outBufferMode == ZSTD_bm_stable)  /* OR we are allowed to return dstSizeTooSmall */
               && (zcs->inBuffPos == 0) ) {
                 /* shortcut to compression pass directly into output buffer */
                 size_t const cSize = ZSTD_compressEnd(zcs,
@@ -3843,8 +5325,9 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
                 ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
                 someMoreWork = 0; break;
             }
-            /* complete loading into inBuffer */
-            {   size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
+            /* complete loading into inBuffer in buffered mode */
+            if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) {
+                size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
                 size_t const loaded = ZSTD_limitCopy(
                                         zcs->inBuff + zcs->inBuffPos, toLoad,
                                         ip, iend-ip);
@@ -3864,31 +5347,49 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
             }
             /* compress current block (note : this stage cannot be stopped in the middle) */
             DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
-            {   void* cDst;
+            {   int const inputBuffered = (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered);
+                void* cDst;
                 size_t cSize;
-                size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
                 size_t oSize = oend-op;
-                unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
-                if (oSize >= ZSTD_compressBound(iSize))
+                size_t const iSize = inputBuffered
+                    ? zcs->inBuffPos - zcs->inToCompress
+                    : MIN((size_t)(iend - ip), zcs->blockSize);
+                if (oSize >= ZSTD_compressBound(iSize) || zcs->appliedParams.outBufferMode == ZSTD_bm_stable)
                     cDst = op;   /* compress into output buffer, to skip flush stage */
                 else
                     cDst = zcs->outBuff, oSize = zcs->outBuffSize;
-                cSize = lastBlock ?
-                        ZSTD_compressEnd(zcs, cDst, oSize,
-                                    zcs->inBuff + zcs->inToCompress, iSize) :
-                        ZSTD_compressContinue(zcs, cDst, oSize,
-                                    zcs->inBuff + zcs->inToCompress, iSize);
-                FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed");
-                zcs->frameEnded = lastBlock;
-                /* prepare next block */
-                zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
-                if (zcs->inBuffTarget > zcs->inBuffSize)
-                    zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
-                DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
-                         (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize);
-                if (!lastBlock)
-                    assert(zcs->inBuffTarget <= zcs->inBuffSize);
-                zcs->inToCompress = zcs->inBuffPos;
+                if (inputBuffered) {
+                    unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
+                    cSize = lastBlock ?
+                            ZSTD_compressEnd(zcs, cDst, oSize,
+                                        zcs->inBuff + zcs->inToCompress, iSize) :
+                            ZSTD_compressContinue(zcs, cDst, oSize,
+                                        zcs->inBuff + zcs->inToCompress, iSize);
+                    FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed");
+                    zcs->frameEnded = lastBlock;
+                    /* prepare next block */
+                    zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
+                    if (zcs->inBuffTarget > zcs->inBuffSize)
+                        zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
+                    DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
+                            (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize);
+                    if (!lastBlock)
+                        assert(zcs->inBuffTarget <= zcs->inBuffSize);
+                    zcs->inToCompress = zcs->inBuffPos;
+                } else {
+                    unsigned const lastBlock = (ip + iSize == iend);
+                    assert(flushMode == ZSTD_e_end /* Already validated */);
+                    cSize = lastBlock ?
+                            ZSTD_compressEnd(zcs, cDst, oSize, ip, iSize) :
+                            ZSTD_compressContinue(zcs, cDst, oSize, ip, iSize);
+                    /* Consume the input prior to error checking to mirror buffered mode. */
+                    if (iSize > 0)
+                        ip += iSize;
+                    FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed");
+                    zcs->frameEnded = lastBlock;
+                    if (lastBlock)
+                        assert(ip == iend);
+                }
                 if (cDst == op) {  /* no need to flush */
                     op += cSize;
                     if (zcs->frameEnded) {
@@ -3905,6 +5406,7 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
            /* fall-through */
         case zcss_flush:
             DEBUGLOG(5, "flush stage");
+            assert(zcs->appliedParams.outBufferMode == ZSTD_bm_buffered);
             {   size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
                 size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op),
                             zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
@@ -3959,6 +5461,135 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf
     return ZSTD_nextInputSizeHint_MTorST(zcs);
 }
 
+/* After a compression call set the expected input/output buffer.
+ * This is validated at the start of the next compression call.
+ */
+static void ZSTD_setBufferExpectations(ZSTD_CCtx* cctx, ZSTD_outBuffer const* output, ZSTD_inBuffer const* input)
+{
+    if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) {
+        cctx->expectedInBuffer = *input;
+    }
+    if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) {
+        cctx->expectedOutBufferSize = output->size - output->pos;
+    }
+}
+
+/* Validate that the input/output buffers match the expectations set by
+ * ZSTD_setBufferExpectations.
+ */
+static size_t ZSTD_checkBufferStability(ZSTD_CCtx const* cctx,
+                                        ZSTD_outBuffer const* output,
+                                        ZSTD_inBuffer const* input,
+                                        ZSTD_EndDirective endOp)
+{
+    if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) {
+        ZSTD_inBuffer const expect = cctx->expectedInBuffer;
+        if (expect.src != input->src || expect.pos != input->pos || expect.size != input->size)
+            RETURN_ERROR(srcBuffer_wrong, "ZSTD_c_stableInBuffer enabled but input differs!");
+        if (endOp != ZSTD_e_end)
+            RETURN_ERROR(srcBuffer_wrong, "ZSTD_c_stableInBuffer can only be used with ZSTD_e_end!");
+    }
+    if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) {
+        size_t const outBufferSize = output->size - output->pos;
+        if (cctx->expectedOutBufferSize != outBufferSize)
+            RETURN_ERROR(dstBuffer_wrong, "ZSTD_c_stableOutBuffer enabled but output size differs!");
+    }
+    return 0;
+}
+
+static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
+                                             ZSTD_EndDirective endOp,
+                                             size_t inSize) {
+    ZSTD_CCtx_params params = cctx->requestedParams;
+    ZSTD_prefixDict const prefixDict = cctx->prefixDict;
+    FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */
+    ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));   /* single usage */
+    assert(prefixDict.dict==NULL || cctx->cdict==NULL);    /* only one can be set */
+    if (cctx->cdict && !cctx->localDict.cdict) {
+        /* Let the cdict's compression level take priority over the requested params.
+         * But do not take the cdict's compression level if the "cdict" is actually a localDict
+         * generated from ZSTD_initLocalDict().
+         */
+        params.compressionLevel = cctx->cdict->compressionLevel;
+    }
+    DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage");
+    if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1;  /* auto-fix pledgedSrcSize */
+    {
+        size_t const dictSize = prefixDict.dict
+                ? prefixDict.dictSize
+                : (cctx->cdict ? cctx->cdict->dictContentSize : 0);
+        ZSTD_cParamMode_e const mode = ZSTD_getCParamMode(cctx->cdict, &params, cctx->pledgedSrcSizePlusOne - 1);
+        params.cParams = ZSTD_getCParamsFromCCtxParams(
+                &params, cctx->pledgedSrcSizePlusOne-1,
+                dictSize, mode);
+    }
+
+    if (ZSTD_CParams_shouldEnableLdm(&params.cParams)) {
+        /* Enable LDM by default for optimal parser and window size >= 128MB */
+        DEBUGLOG(4, "LDM enabled by default (window size >= 128MB, strategy >= btopt)");
+        params.ldmParams.enableLdm = 1;
+    }
+
+    if (ZSTD_CParams_useBlockSplitter(&params.cParams)) {
+        DEBUGLOG(4, "Block splitter enabled by default (window size >= 128K, strategy >= btopt)");
+        params.splitBlocks = 1;
+    }
+
+    params.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params.useRowMatchFinder, &params.cParams);
+
+#ifdef ZSTD_MULTITHREAD
+    if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
+        params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
+    }
+    if (params.nbWorkers > 0) {
+#if ZSTD_TRACE
+        cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0;
+#endif
+        /* mt context creation */
+        if (cctx->mtctx == NULL) {
+            DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u",
+                        params.nbWorkers);
+            cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem, cctx->pool);
+            RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!");
+        }
+        /* mt compression */
+        DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers);
+        FORWARD_IF_ERROR( ZSTDMT_initCStream_internal(
+                    cctx->mtctx,
+                    prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
+                    cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , "");
+        cctx->dictID = cctx->cdict ? cctx->cdict->dictID : 0;
+        cctx->dictContentSize = cctx->cdict ? cctx->cdict->dictContentSize : prefixDict.dictSize;
+        cctx->consumedSrcSize = 0;
+        cctx->producedCSize = 0;
+        cctx->streamStage = zcss_load;
+        cctx->appliedParams = params;
+    } else
+#endif
+    {   U64 const pledgedSrcSize = cctx->pledgedSrcSizePlusOne - 1;
+        assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
+        FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx,
+                prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, ZSTD_dtlm_fast,
+                cctx->cdict,
+                &params, pledgedSrcSize,
+                ZSTDb_buffered) , "");
+        assert(cctx->appliedParams.nbWorkers == 0);
+        cctx->inToCompress = 0;
+        cctx->inBuffPos = 0;
+        if (cctx->appliedParams.inBufferMode == ZSTD_bm_buffered) {
+            /* for small input: avoid automatic flush on reaching end of block, since
+            * it would require to add a 3-bytes null block to end frame
+            */
+            cctx->inBuffTarget = cctx->blockSize + (cctx->blockSize == pledgedSrcSize);
+        } else {
+            cctx->inBuffTarget = 0;
+        }
+        cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
+        cctx->streamStage = zcss_load;
+        cctx->frameEnded = 0;
+    }
+    return 0;
+}
 
 size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
                              ZSTD_outBuffer* output,
@@ -3967,82 +5598,69 @@ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
 {
     DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp);
     /* check conditions */
-    RETURN_ERROR_IF(output->pos > output->size, GENERIC, "invalid buffer");
-    RETURN_ERROR_IF(input->pos  > input->size, GENERIC, "invalid buffer");
-    assert(cctx!=NULL);
+    RETURN_ERROR_IF(output->pos > output->size, dstSize_tooSmall, "invalid output buffer");
+    RETURN_ERROR_IF(input->pos  > input->size, srcSize_wrong, "invalid input buffer");
+    RETURN_ERROR_IF((U32)endOp > (U32)ZSTD_e_end, parameter_outOfBound, "invalid endDirective");
+    assert(cctx != NULL);
 
     /* transparent initialization stage */
     if (cctx->streamStage == zcss_init) {
-        ZSTD_CCtx_params params = cctx->requestedParams;
-        ZSTD_prefixDict const prefixDict = cctx->prefixDict;
-        FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */
-        memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));   /* single usage */
-        assert(prefixDict.dict==NULL || cctx->cdict==NULL);    /* only one can be set */
-        DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage");
-        if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1;  /* auto-fix pledgedSrcSize */
-        params.cParams = ZSTD_getCParamsFromCCtxParams(
-                &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
-
-
-#ifdef ZSTD_MULTITHREAD
-        if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
-            params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
-        }
-        if (params.nbWorkers > 0) {
-            /* mt context creation */
-            if (cctx->mtctx == NULL) {
-                DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u",
-                            params.nbWorkers);
-                cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem);
-                RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!");
-            }
-            /* mt compression */
-            DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers);
-            FORWARD_IF_ERROR( ZSTDMT_initCStream_internal(
-                        cctx->mtctx,
-                        prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
-                        cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , "");
-            cctx->streamStage = zcss_load;
-            cctx->appliedParams.nbWorkers = params.nbWorkers;
-        } else
-#endif
-        {   FORWARD_IF_ERROR( ZSTD_resetCStream_internal(cctx,
-                            prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
-                            cctx->cdict,
-                            params, cctx->pledgedSrcSizePlusOne-1) , "");
-            assert(cctx->streamStage == zcss_load);
-            assert(cctx->appliedParams.nbWorkers == 0);
-    }   }
+        FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, endOp, input->size), "CompressStream2 initialization failed");
+        ZSTD_setBufferExpectations(cctx, output, input);    /* Set initial buffer expectations now that we've initialized */
+    }
     /* end of transparent initialization stage */
 
+    FORWARD_IF_ERROR(ZSTD_checkBufferStability(cctx, output, input, endOp), "invalid buffers");
     /* compression stage */
 #ifdef ZSTD_MULTITHREAD
     if (cctx->appliedParams.nbWorkers > 0) {
-        int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end);
         size_t flushMin;
-        assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */);
         if (cctx->cParamsChanged) {
             ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams);
             cctx->cParamsChanged = 0;
         }
-        do {
+        for (;;) {
+            size_t const ipos = input->pos;
+            size_t const opos = output->pos;
             flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
+            cctx->consumedSrcSize += (U64)(input->pos - ipos);
+            cctx->producedCSize += (U64)(output->pos - opos);
             if ( ZSTD_isError(flushMin)
               || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
+                if (flushMin == 0)
+                    ZSTD_CCtx_trace(cctx, 0);
                 ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
             }
             FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed");
-        } while (forceMaxProgress && flushMin != 0 && output->pos < output->size);
+
+            if (endOp == ZSTD_e_continue) {
+                /* We only require some progress with ZSTD_e_continue, not maximal progress.
+                 * We're done if we've consumed or produced any bytes, or either buffer is
+                 * full.
+                 */
+                if (input->pos != ipos || output->pos != opos || input->pos == input->size || output->pos == output->size)
+                    break;
+            } else {
+                assert(endOp == ZSTD_e_flush || endOp == ZSTD_e_end);
+                /* We require maximal progress. We're done when the flush is complete or the
+                 * output buffer is full.
+                 */
+                if (flushMin == 0 || output->pos == output->size)
+                    break;
+            }
+        }
         DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic");
         /* Either we don't require maximum forward progress, we've finished the
          * flush, or we are out of output space.
          */
-        assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size);
+        assert(endOp == ZSTD_e_continue || flushMin == 0 || output->pos == output->size);
+        ZSTD_setBufferExpectations(cctx, output, input);
         return flushMin;
     }
 #endif
     FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , "");
     DEBUGLOG(5, "completed ZSTD_compressStream2");
+    ZSTD_setBufferExpectations(cctx, output, input);
     return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
 }
 
@@ -4065,14 +5683,22 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx,
                       void* dst, size_t dstCapacity,
                       const void* src, size_t srcSize)
 {
+    ZSTD_bufferMode_e const originalInBufferMode = cctx->requestedParams.inBufferMode;
+    ZSTD_bufferMode_e const originalOutBufferMode = cctx->requestedParams.outBufferMode;
     DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize);
     ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
+    /* Enable stable input/output buffers. */
+    cctx->requestedParams.inBufferMode = ZSTD_bm_stable;
+    cctx->requestedParams.outBufferMode = ZSTD_bm_stable;
     {   size_t oPos = 0;
         size_t iPos = 0;
         size_t const result = ZSTD_compressStream2_simpleArgs(cctx,
                                         dst, dstCapacity, &oPos,
                                         src, srcSize, &iPos,
                                         ZSTD_e_end);
+        /* Reset to the original values. */
+        cctx->requestedParams.inBufferMode = originalInBufferMode;
+        cctx->requestedParams.outBufferMode = originalOutBufferMode;
         FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed");
         if (result != 0) {  /* compression not completed, due to lack of output space */
             assert(oPos == dstCapacity);
@@ -4083,6 +5709,409 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx,
     }
 }
 
+typedef struct {
+    U32 idx;             /* Index in array of ZSTD_Sequence */
+    U32 posInSequence;   /* Position within sequence at idx */
+    size_t posInSrc;        /* Number of bytes given by sequences provided so far */
+} ZSTD_sequencePosition;
+
+/* Returns a ZSTD error code if sequence is not valid */
+static size_t ZSTD_validateSequence(U32 offCode, U32 matchLength,
+                                    size_t posInSrc, U32 windowLog, size_t dictSize, U32 minMatch) {
+    size_t offsetBound;
+    U32 windowSize = 1 << windowLog;
+    /* posInSrc represents the amount of data the the decoder would decode up to this point.
+     * As long as the amount of data decoded is less than or equal to window size, offsets may be
+     * larger than the total length of output decoded in order to reference the dict, even larger than
+     * window size. After output surpasses windowSize, we're limited to windowSize offsets again.
+     */
+    offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize;
+    RETURN_ERROR_IF(offCode > offsetBound + ZSTD_REP_MOVE, corruption_detected, "Offset too large!");
+    RETURN_ERROR_IF(matchLength < minMatch, corruption_detected, "Matchlength too small");
+    return 0;
+}
+
+/* Returns an offset code, given a sequence's raw offset, the ongoing repcode array, and whether litLength == 0 */
+static U32 ZSTD_finalizeOffCode(U32 rawOffset, const U32 rep[ZSTD_REP_NUM], U32 ll0) {
+    U32 offCode = rawOffset + ZSTD_REP_MOVE;
+    U32 repCode = 0;
+
+    if (!ll0 && rawOffset == rep[0]) {
+        repCode = 1;
+    } else if (rawOffset == rep[1]) {
+        repCode = 2 - ll0;
+    } else if (rawOffset == rep[2]) {
+        repCode = 3 - ll0;
+    } else if (ll0 && rawOffset == rep[0] - 1) {
+        repCode = 3;
+    }
+    if (repCode) {
+        /* ZSTD_storeSeq expects a number in the range [0, 2] to represent a repcode */
+        offCode = repCode - 1;
+    }
+    return offCode;
+}
+
+/* Returns 0 on success, and a ZSTD_error otherwise. This function scans through an array of
+ * ZSTD_Sequence, storing the sequences it finds, until it reaches a block delimiter.
+ */
+static size_t ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos,
+                                                             const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
+                                                             const void* src, size_t blockSize) {
+    U32 idx = seqPos->idx;
+    BYTE const* ip = (BYTE const*)(src);
+    const BYTE* const iend = ip + blockSize;
+    repcodes_t updatedRepcodes;
+    U32 dictSize;
+    U32 litLength;
+    U32 matchLength;
+    U32 ll0;
+    U32 offCode;
+
+    if (cctx->cdict) {
+        dictSize = (U32)cctx->cdict->dictContentSize;
+    } else if (cctx->prefixDict.dict) {
+        dictSize = (U32)cctx->prefixDict.dictSize;
+    } else {
+        dictSize = 0;
+    }
+    ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t));
+    for (; (inSeqs[idx].matchLength != 0 || inSeqs[idx].offset != 0) && idx < inSeqsSize; ++idx) {
+        litLength = inSeqs[idx].litLength;
+        matchLength = inSeqs[idx].matchLength;
+        ll0 = litLength == 0;
+        offCode = ZSTD_finalizeOffCode(inSeqs[idx].offset, updatedRepcodes.rep, ll0);
+        updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep, offCode, ll0);
+
+        DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offCode, matchLength, litLength);
+        if (cctx->appliedParams.validateSequences) {
+            seqPos->posInSrc += litLength + matchLength;
+            FORWARD_IF_ERROR(ZSTD_validateSequence(offCode, matchLength, seqPos->posInSrc,
+                                                cctx->appliedParams.cParams.windowLog, dictSize,
+                                                cctx->appliedParams.cParams.minMatch),
+                                                "Sequence validation failed");
+        }
+        RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation,
+                        "Not enough memory allocated. Try adjusting ZSTD_c_minMatch.");
+        ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offCode, matchLength - MINMATCH);
+        ip += matchLength + litLength;
+    }
+    ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t));
+
+    if (inSeqs[idx].litLength) {
+        DEBUGLOG(6, "Storing last literals of size: %u", inSeqs[idx].litLength);
+        ZSTD_storeLastLiterals(&cctx->seqStore, ip, inSeqs[idx].litLength);
+        ip += inSeqs[idx].litLength;
+        seqPos->posInSrc += inSeqs[idx].litLength;
+    }
+    RETURN_ERROR_IF(ip != iend, corruption_detected, "Blocksize doesn't agree with block delimiter!");
+    seqPos->idx = idx+1;
+    return 0;
+}
+
+/* Returns the number of bytes to move the current read position back by. Only non-zero
+ * if we ended up splitting a sequence. Otherwise, it may return a ZSTD error if something
+ * went wrong.
+ *
+ * This function will attempt to scan through blockSize bytes represented by the sequences
+ * in inSeqs, storing any (partial) sequences.
+ *
+ * Occasionally, we may want to change the actual number of bytes we consumed from inSeqs to
+ * avoid splitting a match, or to avoid splitting a match such that it would produce a match
+ * smaller than MINMATCH. In this case, we return the number of bytes that we didn't read from this block.
+ */
+static size_t ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos,
+                                                       const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
+                                                       const void* src, size_t blockSize) {
+    U32 idx = seqPos->idx;
+    U32 startPosInSequence = seqPos->posInSequence;
+    U32 endPosInSequence = seqPos->posInSequence + (U32)blockSize;
+    size_t dictSize;
+    BYTE const* ip = (BYTE const*)(src);
+    BYTE const* iend = ip + blockSize;  /* May be adjusted if we decide to process fewer than blockSize bytes */
+    repcodes_t updatedRepcodes;
+    U32 bytesAdjustment = 0;
+    U32 finalMatchSplit = 0;
+    U32 litLength;
+    U32 matchLength;
+    U32 rawOffset;
+    U32 offCode;
+
+    if (cctx->cdict) {
+        dictSize = cctx->cdict->dictContentSize;
+    } else if (cctx->prefixDict.dict) {
+        dictSize = cctx->prefixDict.dictSize;
+    } else {
+        dictSize = 0;
+    }
+    DEBUGLOG(5, "ZSTD_copySequencesToSeqStore: idx: %u PIS: %u blockSize: %zu", idx, startPosInSequence, blockSize);
+    DEBUGLOG(5, "Start seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength);
+    ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t));
+    while (endPosInSequence && idx < inSeqsSize && !finalMatchSplit) {
+        const ZSTD_Sequence currSeq = inSeqs[idx];
+        litLength = currSeq.litLength;
+        matchLength = currSeq.matchLength;
+        rawOffset = currSeq.offset;
+
+        /* Modify the sequence depending on where endPosInSequence lies */
+        if (endPosInSequence >= currSeq.litLength + currSeq.matchLength) {
+            if (startPosInSequence >= litLength) {
+                startPosInSequence -= litLength;
+                litLength = 0;
+                matchLength -= startPosInSequence;
+            } else {
+                litLength -= startPosInSequence;
+            }
+            /* Move to the next sequence */
+            endPosInSequence -= currSeq.litLength + currSeq.matchLength;
+            startPosInSequence = 0;
+            idx++;
+        } else {
+            /* This is the final (partial) sequence we're adding from inSeqs, and endPosInSequence
+               does not reach the end of the match. So, we have to split the sequence */
+            DEBUGLOG(6, "Require a split: diff: %u, idx: %u PIS: %u",
+                     currSeq.litLength + currSeq.matchLength - endPosInSequence, idx, endPosInSequence);
+            if (endPosInSequence > litLength) {
+                U32 firstHalfMatchLength;
+                litLength = startPosInSequence >= litLength ? 0 : litLength - startPosInSequence;
+                firstHalfMatchLength = endPosInSequence - startPosInSequence - litLength;
+                if (matchLength > blockSize && firstHalfMatchLength >= cctx->appliedParams.cParams.minMatch) {
+                    /* Only ever split the match if it is larger than the block size */
+                    U32 secondHalfMatchLength = currSeq.matchLength + currSeq.litLength - endPosInSequence;
+                    if (secondHalfMatchLength < cctx->appliedParams.cParams.minMatch) {
+                        /* Move the endPosInSequence backward so that it creates match of minMatch length */
+                        endPosInSequence -= cctx->appliedParams.cParams.minMatch - secondHalfMatchLength;
+                        bytesAdjustment = cctx->appliedParams.cParams.minMatch - secondHalfMatchLength;
+                        firstHalfMatchLength -= bytesAdjustment;
+                    }
+                    matchLength = firstHalfMatchLength;
+                    /* Flag that we split the last match - after storing the sequence, exit the loop,
+                       but keep the value of endPosInSequence */
+                    finalMatchSplit = 1;
+                } else {
+                    /* Move the position in sequence backwards so that we don't split match, and break to store
+                     * the last literals. We use the original currSeq.litLength as a marker for where endPosInSequence
+                     * should go. We prefer to do this whenever it is not necessary to split the match, or if doing so
+                     * would cause the first half of the match to be too small
+                     */
+                    bytesAdjustment = endPosInSequence - currSeq.litLength;
+                    endPosInSequence = currSeq.litLength;
+                    break;
+                }
+            } else {
+                /* This sequence ends inside the literals, break to store the last literals */
+                break;
+            }
+        }
+        /* Check if this offset can be represented with a repcode */
+        {   U32 ll0 = (litLength == 0);
+            offCode = ZSTD_finalizeOffCode(rawOffset, updatedRepcodes.rep, ll0);
+            updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep, offCode, ll0);
+        }
+
+        if (cctx->appliedParams.validateSequences) {
+            seqPos->posInSrc += litLength + matchLength;
+            FORWARD_IF_ERROR(ZSTD_validateSequence(offCode, matchLength, seqPos->posInSrc,
+                                                   cctx->appliedParams.cParams.windowLog, dictSize,
+                                                   cctx->appliedParams.cParams.minMatch),
+                                                   "Sequence validation failed");
+        }
+        DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offCode, matchLength, litLength);
+        RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation,
+                        "Not enough memory allocated. Try adjusting ZSTD_c_minMatch.");
+        ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offCode, matchLength - MINMATCH);
+        ip += matchLength + litLength;
+    }
+    DEBUGLOG(5, "Ending seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength);
+    assert(idx == inSeqsSize || endPosInSequence <= inSeqs[idx].litLength + inSeqs[idx].matchLength);
+    seqPos->idx = idx;
+    seqPos->posInSequence = endPosInSequence;
+    ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t));
+
+    iend -= bytesAdjustment;
+    if (ip != iend) {
+        /* Store any last literals */
+        U32 lastLLSize = (U32)(iend - ip);
+        assert(ip <= iend);
+        DEBUGLOG(6, "Storing last literals of size: %u", lastLLSize);
+        ZSTD_storeLastLiterals(&cctx->seqStore, ip, lastLLSize);
+        seqPos->posInSrc += lastLLSize;
+    }
+
+    return bytesAdjustment;
+}
+
+typedef size_t (*ZSTD_sequenceCopier) (ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos,
+                                       const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
+                                       const void* src, size_t blockSize);
+static ZSTD_sequenceCopier ZSTD_selectSequenceCopier(ZSTD_sequenceFormat_e mode) {
+    ZSTD_sequenceCopier sequenceCopier = NULL;
+    assert(ZSTD_cParam_withinBounds(ZSTD_c_blockDelimiters, mode));
+    if (mode == ZSTD_sf_explicitBlockDelimiters) {
+        return ZSTD_copySequencesToSeqStoreExplicitBlockDelim;
+    } else if (mode == ZSTD_sf_noBlockDelimiters) {
+        return ZSTD_copySequencesToSeqStoreNoBlockDelim;
+    }
+    assert(sequenceCopier != NULL);
+    return sequenceCopier;
+}
+
+/* Compress, block-by-block, all of the sequences given.
+ *
+ * Returns the cumulative size of all compressed blocks (including their headers), otherwise a ZSTD error.
+ */
+static size_t ZSTD_compressSequences_internal(ZSTD_CCtx* cctx,
+                                              void* dst, size_t dstCapacity,
+                                              const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
+                                              const void* src, size_t srcSize) {
+    size_t cSize = 0;
+    U32 lastBlock;
+    size_t blockSize;
+    size_t compressedSeqsSize;
+    size_t remaining = srcSize;
+    ZSTD_sequencePosition seqPos = {0, 0, 0};
+
+    BYTE const* ip = (BYTE const*)src;
+    BYTE* op = (BYTE*)dst;
+    ZSTD_sequenceCopier sequenceCopier = ZSTD_selectSequenceCopier(cctx->appliedParams.blockDelimiters);
+
+    DEBUGLOG(4, "ZSTD_compressSequences_internal srcSize: %zu, inSeqsSize: %zu", srcSize, inSeqsSize);
+    /* Special case: empty frame */
+    if (remaining == 0) {
+        U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1);
+        RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "No room for empty frame block header");
+        MEM_writeLE32(op, cBlockHeader24);
+        op += ZSTD_blockHeaderSize;
+        dstCapacity -= ZSTD_blockHeaderSize;
+        cSize += ZSTD_blockHeaderSize;
+    }
+
+    while (remaining) {
+        size_t cBlockSize;
+        size_t additionalByteAdjustment;
+        lastBlock = remaining <= cctx->blockSize;
+        blockSize = lastBlock ? (U32)remaining : (U32)cctx->blockSize;
+        ZSTD_resetSeqStore(&cctx->seqStore);
+        DEBUGLOG(4, "Working on new block. Blocksize: %zu", blockSize);
+
+        additionalByteAdjustment = sequenceCopier(cctx, &seqPos, inSeqs, inSeqsSize, ip, blockSize);
+        FORWARD_IF_ERROR(additionalByteAdjustment, "Bad sequence copy");
+        blockSize -= additionalByteAdjustment;
+
+        /* If blocks are too small, emit as a nocompress block */
+        if (blockSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
+            cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
+            FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed");
+            DEBUGLOG(4, "Block too small, writing out nocompress block: cSize: %zu", cBlockSize);
+            cSize += cBlockSize;
+            ip += blockSize;
+            op += cBlockSize;
+            remaining -= blockSize;
+            dstCapacity -= cBlockSize;
+            continue;
+        }
+
+        compressedSeqsSize = ZSTD_entropyCompressSeqStore(&cctx->seqStore,
+                                &cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy,
+                                &cctx->appliedParams,
+                                op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize,
+                                blockSize,
+                                cctx->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
+                                cctx->bmi2);
+        FORWARD_IF_ERROR(compressedSeqsSize, "Compressing sequences of block failed");
+        DEBUGLOG(4, "Compressed sequences size: %zu", compressedSeqsSize);
+
+        if (!cctx->isFirstBlock &&
+            ZSTD_maybeRLE(&cctx->seqStore) &&
+            ZSTD_isRLE((BYTE const*)src, srcSize)) {
+            /* We don't want to emit our first block as a RLE even if it qualifies because
+            * doing so will cause the decoder (cli only) to throw a "should consume all input error."
+            * This is only an issue for zstd <= v1.4.3
+            */
+            compressedSeqsSize = 1;
+        }
+
+        if (compressedSeqsSize == 0) {
+            /* ZSTD_noCompressBlock writes the block header as well */
+            cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
+            FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed");
+            DEBUGLOG(4, "Writing out nocompress block, size: %zu", cBlockSize);
+        } else if (compressedSeqsSize == 1) {
+            cBlockSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, blockSize, lastBlock);
+            FORWARD_IF_ERROR(cBlockSize, "RLE compress block failed");
+            DEBUGLOG(4, "Writing out RLE block, size: %zu", cBlockSize);
+        } else {
+            U32 cBlockHeader;
+            /* Error checking and repcodes update */
+            ZSTD_blockState_confirmRepcodesAndEntropyTables(&cctx->blockState);
+            if (cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
+                cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
+
+            /* Write block header into beginning of block*/
+            cBlockHeader = lastBlock + (((U32)bt_compressed)<<1) + (U32)(compressedSeqsSize << 3);
+            MEM_writeLE24(op, cBlockHeader);
+            cBlockSize = ZSTD_blockHeaderSize + compressedSeqsSize;
+            DEBUGLOG(4, "Writing out compressed block, size: %zu", cBlockSize);
+        }
+
+        cSize += cBlockSize;
+        DEBUGLOG(4, "cSize running total: %zu", cSize);
+
+        if (lastBlock) {
+            break;
+        } else {
+            ip += blockSize;
+            op += cBlockSize;
+            remaining -= blockSize;
+            dstCapacity -= cBlockSize;
+            cctx->isFirstBlock = 0;
+        }
+    }
+
+    return cSize;
+}
+
+size_t ZSTD_compressSequences(ZSTD_CCtx* const cctx, void* dst, size_t dstCapacity,
+                              const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
+                              const void* src, size_t srcSize) {
+    BYTE* op = (BYTE*)dst;
+    size_t cSize = 0;
+    size_t compressedBlocksSize = 0;
+    size_t frameHeaderSize = 0;
+
+    /* Transparent initialization stage, same as compressStream2() */
+    DEBUGLOG(3, "ZSTD_compressSequences()");
+    assert(cctx != NULL);
+    FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, ZSTD_e_end, srcSize), "CCtx initialization failed");
+    /* Begin writing output, starting with frame header */
+    frameHeaderSize = ZSTD_writeFrameHeader(op, dstCapacity, &cctx->appliedParams, srcSize, cctx->dictID);
+    op += frameHeaderSize;
+    dstCapacity -= frameHeaderSize;
+    cSize += frameHeaderSize;
+    if (cctx->appliedParams.fParams.checksumFlag && srcSize) {
+        XXH64_update(&cctx->xxhState, src, srcSize);
+    }
+    /* cSize includes block header size and compressed sequences size */
+    compressedBlocksSize = ZSTD_compressSequences_internal(cctx,
+                                                           op, dstCapacity,
+                                                           inSeqs, inSeqsSize,
+                                                           src, srcSize);
+    FORWARD_IF_ERROR(compressedBlocksSize, "Compressing blocks failed!");
+    cSize += compressedBlocksSize;
+    dstCapacity -= compressedBlocksSize;
+
+    if (cctx->appliedParams.fParams.checksumFlag) {
+        U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
+        RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum");
+        DEBUGLOG(4, "Write checksum : %08X", (unsigned)checksum);
+        MEM_writeLE32((char*)dst + cSize, checksum);
+        cSize += 4;
+    }
+
+    DEBUGLOG(3, "Final compressed size: %zu", cSize);
+    return cSize;
+}
+
 /*======   Finalize   ======*/
 
 /*! ZSTD_flushStream() :
@@ -4115,6 +6144,7 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
 #define ZSTD_MAX_CLEVEL     22
 int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
 int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; }
+int ZSTD_defaultCLevel(void) { return ZSTD_CLEVEL_DEFAULT; }
 
 static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
 {   /* "default" - for any srcSize > 256 KB */
@@ -4223,25 +6253,110 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
 },
 };
 
+static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel, size_t const dictSize)
+{
+    ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, 0, dictSize, ZSTD_cpm_createCDict);
+    switch (cParams.strategy) {
+        case ZSTD_fast:
+        case ZSTD_dfast:
+            break;
+        case ZSTD_greedy:
+        case ZSTD_lazy:
+        case ZSTD_lazy2:
+            cParams.hashLog += ZSTD_LAZY_DDSS_BUCKET_LOG;
+            break;
+        case ZSTD_btlazy2:
+        case ZSTD_btopt:
+        case ZSTD_btultra:
+        case ZSTD_btultra2:
+            break;
+    }
+    return cParams;
+}
+
+static int ZSTD_dedicatedDictSearch_isSupported(
+        ZSTD_compressionParameters const* cParams)
+{
+    return (cParams->strategy >= ZSTD_greedy)
+        && (cParams->strategy <= ZSTD_lazy2)
+        && (cParams->hashLog > cParams->chainLog)
+        && (cParams->chainLog <= 24);
+}
+
+/**
+ * Reverses the adjustment applied to cparams when enabling dedicated dict
+ * search. This is used to recover the params set to be used in the working
+ * context. (Otherwise, those tables would also grow.)
+ */
+static void ZSTD_dedicatedDictSearch_revertCParams(
+        ZSTD_compressionParameters* cParams) {
+    switch (cParams->strategy) {
+        case ZSTD_fast:
+        case ZSTD_dfast:
+            break;
+        case ZSTD_greedy:
+        case ZSTD_lazy:
+        case ZSTD_lazy2:
+            cParams->hashLog -= ZSTD_LAZY_DDSS_BUCKET_LOG;
+            if (cParams->hashLog < ZSTD_HASHLOG_MIN) {
+                cParams->hashLog = ZSTD_HASHLOG_MIN;
+            }
+            break;
+        case ZSTD_btlazy2:
+        case ZSTD_btopt:
+        case ZSTD_btultra:
+        case ZSTD_btultra2:
+            break;
+    }
+}
+
+static U64 ZSTD_getCParamRowSize(U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode)
+{
+    switch (mode) {
+    case ZSTD_cpm_unknown:
+    case ZSTD_cpm_noAttachDict:
+    case ZSTD_cpm_createCDict:
+        break;
+    case ZSTD_cpm_attachDict:
+        dictSize = 0;
+        break;
+    default:
+        assert(0);
+        break;
+    }
+    {   int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN;
+        size_t const addedSize = unknown && dictSize > 0 ? 500 : 0;
+        return unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize;
+    }
+}
+
 /*! ZSTD_getCParams_internal() :
  * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
  *  Note: srcSizeHint 0 means 0, use ZSTD_CONTENTSIZE_UNKNOWN for unknown.
- *        Use dictSize == 0 for unknown or unused. */
-static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
+ *        Use dictSize == 0 for unknown or unused.
+ *  Note: `mode` controls how we treat the `dictSize`. See docs for `ZSTD_cParamMode_e`. */
+static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode)
 {
-    int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN;
-    size_t const addedSize = unknown && dictSize > 0 ? 500 : 0;
-    U64 const rSize = unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize;
+    U64 const rSize = ZSTD_getCParamRowSize(srcSizeHint, dictSize, mode);
     U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB);
-    int row = compressionLevel;
+    int row;
     DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel);
+
+    /* row */
     if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT;   /* 0 == default */
-    if (compressionLevel < 0) row = 0;   /* entry 0 is baseline for fast mode */
-    if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL;
+    else if (compressionLevel < 0) row = 0;   /* entry 0 is baseline for fast mode */
+    else if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL;
+    else row = compressionLevel;
+
     {   ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
-        if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel);   /* acceleration factor */
+        DEBUGLOG(5, "ZSTD_getCParams_internal selected tableID: %u row: %u strat: %u", tableID, row, (U32)cp.strategy);
+        /* acceleration factor */
+        if (compressionLevel < 0) {
+            int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel);
+            cp.targetLength = (unsigned)(-clampedCompressionLevel);
+        }
         /* refine parameters based on srcSize & dictSize */
-        return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize);
+        return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize, mode);
     }
 }
 
@@ -4251,18 +6366,18 @@ static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel,
 ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
 {
     if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
-    return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize);
+    return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown);
 }
 
 /*! ZSTD_getParams() :
  *  same idea as ZSTD_getCParams()
  * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`).
  *  Fields of `ZSTD_frameParameters` are set to default values */
-static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
+static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) {
     ZSTD_parameters params;
-    ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize);
+    ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, mode);
     DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel);
-    memset(&params, 0, sizeof(params));
+    ZSTD_memset(&params, 0, sizeof(params));
     params.cParams = cParams;
     params.fParams.contentSizeFlag = 1;
     return params;
@@ -4274,5 +6389,5 @@ static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned lo
  *  Fields of `ZSTD_frameParameters` are set to default values */
 ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
     if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
-    return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize);
+    return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown);
 }
index db73f6c..3b04fd0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -28,7 +28,6 @@
 extern "C" {
 #endif
 
-
 /*-*************************************
 *  Constants
 ***************************************/
@@ -64,7 +63,7 @@ typedef struct {
 } ZSTD_localDict;
 
 typedef struct {
-    U32 CTable[HUF_CTABLE_SIZE_U32(255)];
+    HUF_CElt CTable[HUF_CTABLE_SIZE_U32(255)];
     HUF_repeat repeatMode;
 } ZSTD_hufCTables_t;
 
@@ -82,12 +81,76 @@ typedef struct {
     ZSTD_fseCTables_t fse;
 } ZSTD_entropyCTables_t;
 
+/***********************************************
+*  Entropy buffer statistics structs and funcs *
+***********************************************/
+/** ZSTD_hufCTablesMetadata_t :
+ *  Stores Literals Block Type for a super-block in hType, and
+ *  huffman tree description in hufDesBuffer.
+ *  hufDesSize refers to the size of huffman tree description in bytes.
+ *  This metadata is populated in ZSTD_buildBlockEntropyStats_literals() */
 typedef struct {
-    U32 off;
-    U32 len;
+    symbolEncodingType_e hType;
+    BYTE hufDesBuffer[ZSTD_MAX_HUF_HEADER_SIZE];
+    size_t hufDesSize;
+} ZSTD_hufCTablesMetadata_t;
+
+/** ZSTD_fseCTablesMetadata_t :
+ *  Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and
+ *  fse tables in fseTablesBuffer.
+ *  fseTablesSize refers to the size of fse tables in bytes.
+ *  This metadata is populated in ZSTD_buildBlockEntropyStats_sequences() */
+typedef struct {
+    symbolEncodingType_e llType;
+    symbolEncodingType_e ofType;
+    symbolEncodingType_e mlType;
+    BYTE fseTablesBuffer[ZSTD_MAX_FSE_HEADERS_SIZE];
+    size_t fseTablesSize;
+    size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */
+} ZSTD_fseCTablesMetadata_t;
+
+typedef struct {
+    ZSTD_hufCTablesMetadata_t hufMetadata;
+    ZSTD_fseCTablesMetadata_t fseMetadata;
+} ZSTD_entropyCTablesMetadata_t;
+
+/** ZSTD_buildBlockEntropyStats() :
+ *  Builds entropy for the block.
+ *  @return : 0 on success or error code */
+size_t ZSTD_buildBlockEntropyStats(seqStore_t* seqStorePtr,
+                             const ZSTD_entropyCTables_t* prevEntropy,
+                                   ZSTD_entropyCTables_t* nextEntropy,
+                             const ZSTD_CCtx_params* cctxParams,
+                                   ZSTD_entropyCTablesMetadata_t* entropyMetadata,
+                                   void* workspace, size_t wkspSize);
+
+/*********************************
+*  Compression internals structs *
+*********************************/
+
+typedef struct {
+    U32 off;            /* Offset code (offset + ZSTD_REP_MOVE) for the match */
+    U32 len;            /* Raw length of match */
 } ZSTD_match_t;
 
 typedef struct {
+    U32 offset;         /* Offset of sequence */
+    U32 litLength;      /* Length of literals prior to match */
+    U32 matchLength;    /* Raw length of match */
+} rawSeq;
+
+typedef struct {
+  rawSeq* seq;          /* The start of the sequences */
+  size_t pos;           /* The index in seq where reading stopped. pos <= size. */
+  size_t posInSequence; /* The position within the sequence at seq[pos] where reading
+                           stopped. posInSequence <= seq[pos].litLength + seq[pos].matchLength */
+  size_t size;          /* The number of sequences. <= capacity. */
+  size_t capacity;      /* The capacity starting from `seq` pointer */
+} rawSeqStore_t;
+
+UNUSED_ATTR static const rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0, 0};
+
+typedef struct {
     int price;
     U32 off;
     U32 mlen;
@@ -125,14 +188,21 @@ typedef struct {
 } ZSTD_compressedBlockState_t;
 
 typedef struct {
-    BYTE const* nextSrc;    /* next block here to continue on current prefix */
-    BYTE const* base;       /* All regular indexes relative to this position */
-    BYTE const* dictBase;   /* extDict indexes relative to this position */
-    U32 dictLimit;          /* below that point, need extDict */
-    U32 lowLimit;           /* below that point, no more valid data */
+    BYTE const* nextSrc;       /* next block here to continue on current prefix */
+    BYTE const* base;          /* All regular indexes relative to this position */
+    BYTE const* dictBase;      /* extDict indexes relative to this position */
+    U32 dictLimit;             /* below that point, need extDict */
+    U32 lowLimit;              /* below that point, no more valid data */
+    U32 nbOverflowCorrections; /* Number of times overflow correction has run since
+                                * ZSTD_window_init(). Useful for debugging coredumps
+                                * and for ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY.
+                                */
 } ZSTD_window_t;
 
 typedef struct ZSTD_matchState_t ZSTD_matchState_t;
+
+#define ZSTD_ROW_HASH_CACHE_SIZE 8       /* Size of prefetching hash cache for row-based matchfinder */
+
 struct ZSTD_matchState_t {
     ZSTD_window_t window;   /* State for window round buffer management */
     U32 loadedDictEnd;      /* index of end of dictionary, within context's referential.
@@ -144,12 +214,24 @@ struct ZSTD_matchState_t {
                              */
     U32 nextToUpdate;       /* index from which to continue table update */
     U32 hashLog3;           /* dispatch table for matches of len==3 : larger == faster, more memory */
+
+    U32 rowHashLog;                          /* For row-based matchfinder: Hashlog based on nb of rows in the hashTable.*/
+    U16* tagTable;                           /* For row-based matchFinder: A row-based table containing the hashes and head index. */
+    U32 hashCache[ZSTD_ROW_HASH_CACHE_SIZE]; /* For row-based matchFinder: a cache of hashes to improve speed */
+
     U32* hashTable;
     U32* hashTable3;
     U32* chainTable;
+
+    U32 forceNonContiguous; /* Non-zero if we should force non-contiguous load for the next window update. */
+
+    int dedicatedDictSearch;  /* Indicates whether this matchState is using the
+                               * dedicated dictionary search structure.
+                               */
     optState_t opt;         /* optimal parser state */
     const ZSTD_matchState_t* dictMatchState;
     ZSTD_compressionParameters cParams;
+    const rawSeqStore_t* ldmSeqStore;
 };
 
 typedef struct {
@@ -164,12 +246,21 @@ typedef struct {
 } ldmEntry_t;
 
 typedef struct {
+    BYTE const* split;
+    U32 hash;
+    U32 checksum;
+    ldmEntry_t* bucket;
+} ldmMatchCandidate_t;
+
+#define LDM_BATCH_SIZE 64
+
+typedef struct {
     ZSTD_window_t window;   /* State for the window round buffer management */
     ldmEntry_t* hashTable;
     U32 loadedDictEnd;
     BYTE* bucketOffsets;    /* Next position in bucket to insert entry */
-    U64 hashPower;          /* Used to compute the rolling hash.
-                             * Depends on ldmParams.minMatchLength */
+    size_t splitIndices[LDM_BATCH_SIZE];
+    ldmMatchCandidate_t matchCandidates[LDM_BATCH_SIZE];
 } ldmState_t;
 
 typedef struct {
@@ -182,19 +273,6 @@ typedef struct {
 } ldmParams_t;
 
 typedef struct {
-    U32 offset;
-    U32 litLength;
-    U32 matchLength;
-} rawSeq;
-
-typedef struct {
-  rawSeq* seq;     /* The start of the sequences */
-  size_t pos;      /* The position where reading stopped. <= size. */
-  size_t size;     /* The number of sequences. <= capacity. */
-  size_t capacity; /* The capacity starting from `seq` pointer */
-} rawSeqStore_t;
-
-typedef struct {
     int collectSequences;
     ZSTD_Sequence* seqStart;
     size_t seqIndex;
@@ -228,17 +306,52 @@ struct ZSTD_CCtx_params_s {
     /* Long distance matching parameters */
     ldmParams_t ldmParams;
 
+    /* Dedicated dict search algorithm trigger */
+    int enableDedicatedDictSearch;
+
+    /* Input/output buffer modes */
+    ZSTD_bufferMode_e inBufferMode;
+    ZSTD_bufferMode_e outBufferMode;
+
+    /* Sequence compression API */
+    ZSTD_sequenceFormat_e blockDelimiters;
+    int validateSequences;
+
+    /* Block splitting */
+    int splitBlocks;
+
+    /* Param for deciding whether to use row-based matchfinder */
+    ZSTD_useRowMatchFinderMode_e useRowMatchFinder;
+
+    /* Always load a dictionary in ext-dict mode (not prefix mode)? */
+    int deterministicRefPrefix;
+
     /* Internal use, for createCCtxParams() and freeCCtxParams() only */
     ZSTD_customMem customMem;
 };  /* typedef'd to ZSTD_CCtx_params within "zstd.h" */
 
+#define COMPRESS_SEQUENCES_WORKSPACE_SIZE (sizeof(unsigned) * (MaxSeq + 2))
+#define ENTROPY_WORKSPACE_SIZE (HUF_WORKSPACE_SIZE + COMPRESS_SEQUENCES_WORKSPACE_SIZE)
+
+/**
+ * Indicates whether this compression proceeds directly from user-provided
+ * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or
+ * whether the context needs to buffer the input/output (ZSTDb_buffered).
+ */
+typedef enum {
+    ZSTDb_not_buffered,
+    ZSTDb_buffered
+} ZSTD_buffered_policy_e;
+
 struct ZSTD_CCtx_s {
     ZSTD_compressionStage_e stage;
     int cParamsChanged;                  /* == 1 if cParams(except wlog) or compression level are changed in requestedParams. Triggers transmission of new params to ZSTDMT (if available) then reset to 0. */
     int bmi2;                            /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */
     ZSTD_CCtx_params requestedParams;
     ZSTD_CCtx_params appliedParams;
+    ZSTD_CCtx_params simpleApiParams;    /* Param storage used by the simple API - not sticky. Must only be used in top-level simple API functions for storage. */
     U32   dictID;
+    size_t dictContentSize;
 
     ZSTD_cwksp workspace; /* manages buffer for dynamic allocations */
     size_t blockSize;
@@ -247,6 +360,7 @@ struct ZSTD_CCtx_s {
     unsigned long long producedCSize;
     XXH64_state_t xxhState;
     ZSTD_customMem customMem;
+    ZSTD_threadPool* pool;
     size_t staticSize;
     SeqCollector seqCollector;
     int isFirstBlock;
@@ -258,7 +372,10 @@ struct ZSTD_CCtx_s {
     size_t maxNbLdmSequences;
     rawSeqStore_t externSeqStore; /* Mutable reference to external sequences */
     ZSTD_blockState_t blockState;
-    U32* entropyWorkspace;  /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
+    U32* entropyWorkspace;  /* entropy workspace of ENTROPY_WORKSPACE_SIZE bytes */
+
+    /* Wether we are streaming or not */
+    ZSTD_buffered_policy_e bufferedPolicy;
 
     /* streaming */
     char*  inBuff;
@@ -273,6 +390,10 @@ struct ZSTD_CCtx_s {
     ZSTD_cStreamStage streamStage;
     U32    frameEnded;
 
+    /* Stable in/out buffer verification */
+    ZSTD_inBuffer expectedInBuffer;
+    size_t expectedOutBufferSize;
+
     /* Dictionary */
     ZSTD_localDict localDict;
     const ZSTD_CDict* cdict;
@@ -282,17 +403,46 @@ struct ZSTD_CCtx_s {
 #ifdef ZSTD_MULTITHREAD
     ZSTDMT_CCtx* mtctx;
 #endif
+
+    /* Tracing */
+#if ZSTD_TRACE
+    ZSTD_TraceCtx traceCtx;
+#endif
 };
 
 typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e;
 
-typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e;
-
+typedef enum {
+    ZSTD_noDict = 0,
+    ZSTD_extDict = 1,
+    ZSTD_dictMatchState = 2,
+    ZSTD_dedicatedDictSearch = 3
+} ZSTD_dictMode_e;
+
+typedef enum {
+    ZSTD_cpm_noAttachDict = 0,  /* Compression with ZSTD_noDict or ZSTD_extDict.
+                                 * In this mode we use both the srcSize and the dictSize
+                                 * when selecting and adjusting parameters.
+                                 */
+    ZSTD_cpm_attachDict = 1,    /* Compression with ZSTD_dictMatchState or ZSTD_dedicatedDictSearch.
+                                 * In this mode we only take the srcSize into account when selecting
+                                 * and adjusting parameters.
+                                 */
+    ZSTD_cpm_createCDict = 2,   /* Creating a CDict.
+                                 * In this mode we take both the source size and the dictionary size
+                                 * into account when selecting and adjusting the parameters.
+                                 */
+    ZSTD_cpm_unknown = 3,       /* ZSTD_getCParams, ZSTD_getParams, ZSTD_adjustParams.
+                                 * We don't know what these parameters are for. We default to the legacy
+                                 * behavior of taking both the source size and the dict size into account
+                                 * when selecting and adjusting parameters.
+                                 */
+} ZSTD_cParamMode_e;
 
 typedef size_t (*ZSTD_blockCompressor) (
         ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
         void const* src, size_t srcSize);
-ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode);
+ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_useRowMatchFinderMode_e rowMatchfinderMode, ZSTD_dictMode_e dictMode);
 
 
 MEM_STATIC U32 ZSTD_LLcode(U32 litLength)
@@ -345,7 +495,7 @@ MEM_STATIC repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 con
             newReps.rep[1] = rep[0];
             newReps.rep[0] = currentOffset;
         } else {   /* repCode == 0 */
-            memcpy(&newReps, rep, sizeof(newReps));
+            ZSTD_memcpy(&newReps, rep, sizeof(newReps));
         }
     }
     return newReps;
@@ -372,7 +522,7 @@ MEM_STATIC size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const voi
     RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity,
                     dstSize_tooSmall, "dst buf too small for uncompressed block");
     MEM_writeLE24(dst, cBlockHeader24);
-    memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
+    ZSTD_memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
     return ZSTD_blockHeaderSize + srcSize;
 }
 
@@ -469,8 +619,8 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera
 
     /* literal Length */
     if (litLength>0xFFFF) {
-        assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
-        seqStorePtr->longLengthID = 1;
+        assert(seqStorePtr->longLengthType == ZSTD_llt_none); /* there can only be a single long length */
+        seqStorePtr->longLengthType = ZSTD_llt_literalLength;
         seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
     }
     seqStorePtr->sequences[0].litLength = (U16)litLength;
@@ -480,8 +630,8 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera
 
     /* match Length */
     if (mlBase>0xFFFF) {
-        assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
-        seqStorePtr->longLengthID = 2;
+        assert(seqStorePtr->longLengthType == ZSTD_llt_none); /* there can only be a single long length */
+        seqStorePtr->longLengthType = ZSTD_llt_matchLength;
         seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
     }
     seqStorePtr->sequences[0].matchLength = (U16)mlBase;
@@ -498,8 +648,12 @@ static unsigned ZSTD_NbCommonBytes (size_t val)
     if (MEM_isLittleEndian()) {
         if (MEM_64bits()) {
 #       if defined(_MSC_VER) && defined(_WIN64)
-            unsigned long r = 0;
-            return _BitScanForward64( &r, (U64)val ) ? (unsigned)(r >> 3) : 0;
+#           if STATIC_BMI2
+                return _tzcnt_u64(val) >> 3;
+#           else
+                unsigned long r = 0;
+                return _BitScanForward64( &r, (U64)val ) ? (unsigned)(r >> 3) : 0;
+#           endif
 #       elif defined(__GNUC__) && (__GNUC__ >= 4)
             return (__builtin_ctzll((U64)val) >> 3);
 #       else
@@ -530,8 +684,12 @@ static unsigned ZSTD_NbCommonBytes (size_t val)
     } else {  /* Big Endian CPU */
         if (MEM_64bits()) {
 #       if defined(_MSC_VER) && defined(_WIN64)
-            unsigned long r = 0;
-            return _BitScanReverse64( &r, val ) ? (unsigned)(r >> 3) : 0;
+#           if STATIC_BMI2
+                           return _lzcnt_u64(val) >> 3;
+#           else
+                           unsigned long r = 0;
+                           return _BitScanReverse64(&r, (U64)val) ? (unsigned)(r >> 3) : 0;
+#           endif
 #       elif defined(__GNUC__) && (__GNUC__ >= 4)
             return (__builtin_clzll(val) >> 3);
 #       else
@@ -626,7 +784,8 @@ static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
 static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
 static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
 
-MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
+MEM_STATIC FORCE_INLINE_ATTR
+size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
 {
     switch(mls)
     {
@@ -723,6 +882,13 @@ MEM_STATIC void ZSTD_window_clear(ZSTD_window_t* window)
     window->dictLimit = end;
 }
 
+MEM_STATIC U32 ZSTD_window_isEmpty(ZSTD_window_t const window)
+{
+    return window.dictLimit == 1 &&
+           window.lowLimit == 1 &&
+           (window.nextSrc - window.base) == 1;
+}
+
 /**
  * ZSTD_window_hasExtDict():
  * Returns non-zero if the window has a non-empty extDict.
@@ -742,20 +908,74 @@ MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms)
     return ZSTD_window_hasExtDict(ms->window) ?
         ZSTD_extDict :
         ms->dictMatchState != NULL ?
-            ZSTD_dictMatchState :
+            (ms->dictMatchState->dedicatedDictSearch ? ZSTD_dedicatedDictSearch : ZSTD_dictMatchState) :
             ZSTD_noDict;
 }
 
+/* Defining this macro to non-zero tells zstd to run the overflow correction
+ * code much more frequently. This is very inefficient, and should only be
+ * used for tests and fuzzers.
+ */
+#ifndef ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY
+#  ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+#    define ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY 1
+#  else
+#    define ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY 0
+#  endif
+#endif
+
+/**
+ * ZSTD_window_canOverflowCorrect():
+ * Returns non-zero if the indices are large enough for overflow correction
+ * to work correctly without impacting compression ratio.
+ */
+MEM_STATIC U32 ZSTD_window_canOverflowCorrect(ZSTD_window_t const window,
+                                              U32 cycleLog,
+                                              U32 maxDist,
+                                              U32 loadedDictEnd,
+                                              void const* src)
+{
+    U32 const cycleSize = 1u << cycleLog;
+    U32 const curr = (U32)((BYTE const*)src - window.base);
+    U32 const minIndexToOverflowCorrect = cycleSize + MAX(maxDist, cycleSize);
+
+    /* Adjust the min index to backoff the overflow correction frequency,
+     * so we don't waste too much CPU in overflow correction. If this
+     * computation overflows we don't really care, we just need to make
+     * sure it is at least minIndexToOverflowCorrect.
+     */
+    U32 const adjustment = window.nbOverflowCorrections + 1;
+    U32 const adjustedIndex = MAX(minIndexToOverflowCorrect * adjustment,
+                                  minIndexToOverflowCorrect);
+    U32 const indexLargeEnough = curr > adjustedIndex;
+
+    /* Only overflow correct early if the dictionary is invalidated already,
+     * so we don't hurt compression ratio.
+     */
+    U32 const dictionaryInvalidated = curr > maxDist + loadedDictEnd;
+
+    return indexLargeEnough && dictionaryInvalidated;
+}
+
 /**
  * ZSTD_window_needOverflowCorrection():
  * Returns non-zero if the indices are getting too large and need overflow
  * protection.
  */
 MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window,
+                                                  U32 cycleLog,
+                                                  U32 maxDist,
+                                                  U32 loadedDictEnd,
+                                                  void const* src,
                                                   void const* srcEnd)
 {
-    U32 const current = (U32)((BYTE const*)srcEnd - window.base);
-    return current > ZSTD_CURRENT_MAX;
+    U32 const curr = (U32)((BYTE const*)srcEnd - window.base);
+    if (ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) {
+        if (ZSTD_window_canOverflowCorrect(window, cycleLog, maxDist, loadedDictEnd, src)) {
+            return 1;
+        }
+    }
+    return curr > ZSTD_CURRENT_MAX;
 }
 
 /**
@@ -766,7 +986,6 @@ MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window,
  *
  * The least significant cycleLog bits of the indices must remain the same,
  * which may be 0. Every index up to maxDist in the past must be valid.
- * NOTE: (maxDist & cycleMask) must be zero.
  */
 MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
                                            U32 maxDist, void const* src)
@@ -790,17 +1009,25 @@ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
      * 3. (cctx->lowLimit + 1<<windowLog) < 1<<32:
      *    windowLog <= 31 ==> 3<<29 + 1<<windowLog < 7<<29 < 1<<32.
      */
-    U32 const cycleMask = (1U << cycleLog) - 1;
-    U32 const current = (U32)((BYTE const*)src - window->base);
-    U32 const currentCycle0 = current & cycleMask;
+    U32 const cycleSize = 1u << cycleLog;
+    U32 const cycleMask = cycleSize - 1;
+    U32 const curr = (U32)((BYTE const*)src - window->base);
+    U32 const currentCycle0 = curr & cycleMask;
     /* Exclude zero so that newCurrent - maxDist >= 1. */
-    U32 const currentCycle1 = currentCycle0 == 0 ? (1U << cycleLog) : currentCycle0;
-    U32 const newCurrent = currentCycle1 + maxDist;
-    U32 const correction = current - newCurrent;
-    assert((maxDist & cycleMask) == 0);
-    assert(current > newCurrent);
-    /* Loose bound, should be around 1<<29 (see above) */
-    assert(correction > 1<<28);
+    U32 const currentCycle1 = currentCycle0 == 0 ? cycleSize : currentCycle0;
+    U32 const newCurrent = currentCycle1 + MAX(maxDist, cycleSize);
+    U32 const correction = curr - newCurrent;
+    /* maxDist must be a power of two so that:
+     *   (newCurrent & cycleMask) == (curr & cycleMask)
+     * This is required to not corrupt the chains / binary tree.
+     */
+    assert((maxDist & (maxDist - 1)) == 0);
+    assert((curr & cycleMask) == (newCurrent & cycleMask));
+    assert(curr > newCurrent);
+    if (!ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) {
+        /* Loose bound, should be around 1<<29 (see above) */
+        assert(correction > 1<<28);
+    }
 
     window->base += correction;
     window->dictBase += correction;
@@ -816,6 +1043,8 @@ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
     assert(window->lowLimit <= newCurrent);
     assert(window->dictLimit <= newCurrent);
 
+    ++window->nbOverflowCorrections;
+
     DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction,
              window->lowLimit);
     return correction;
@@ -919,12 +1148,13 @@ ZSTD_checkDictValidity(const ZSTD_window_t* window,
 }
 
 MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) {
-    memset(window, 0, sizeof(*window));
+    ZSTD_memset(window, 0, sizeof(*window));
     window->base = (BYTE const*)"";
     window->dictBase = (BYTE const*)"";
     window->dictLimit = 1;    /* start from 1, so that 1st position is valid */
     window->lowLimit = 1;     /* it ensures first and later CCtx usages compress the same */
     window->nextSrc = window->base + 1;   /* see issue #1241 */
+    window->nbOverflowCorrections = 0;
 }
 
 /**
@@ -935,7 +1165,8 @@ MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) {
  * Returns non-zero if the segment is contiguous.
  */
 MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
-                                  void const* src, size_t srcSize)
+                                  void const* src, size_t srcSize,
+                                  int forceNonContiguous)
 {
     BYTE const* const ip = (BYTE const*)src;
     U32 contiguous = 1;
@@ -945,7 +1176,7 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
     assert(window->base != NULL);
     assert(window->dictBase != NULL);
     /* Check if blocks follow each other */
-    if (src != window->nextSrc) {
+    if (src != window->nextSrc || forceNonContiguous) {
         /* not contiguous */
         size_t const distanceFromBase = (size_t)(window->nextSrc - window->base);
         DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit);
@@ -973,12 +1204,16 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
 /**
  * Returns the lowest allowed match index. It may either be in the ext-dict or the prefix.
  */
-MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog)
+MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 curr, unsigned windowLog)
 {
     U32    const maxDistance = 1U << windowLog;
     U32    const lowestValid = ms->window.lowLimit;
-    U32    const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid;
+    U32    const withinWindow = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid;
     U32    const isDictionary = (ms->loadedDictEnd != 0);
+    /* When using a dictionary the entire dictionary is valid if a single byte of the dictionary
+     * is within the window. We invalidate the dictionary (and set loadedDictEnd to 0) when it isn't
+     * valid for the entire block. So this check is sufficient to find the lowest valid match index.
+     */
     U32    const matchLowest = isDictionary ? lowestValid : withinWindow;
     return matchLowest;
 }
@@ -986,12 +1221,15 @@ MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 current
 /**
  * Returns the lowest allowed match index in the prefix.
  */
-MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog)
+MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_matchState_t* ms, U32 curr, unsigned windowLog)
 {
     U32    const maxDistance = 1U << windowLog;
     U32    const lowestValid = ms->window.dictLimit;
-    U32    const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid;
+    U32    const withinWindow = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid;
     U32    const isDictionary = (ms->loadedDictEnd != 0);
+    /* When computing the lowest prefix index we need to take the dictionary into account to handle
+     * the edge case where the dictionary and the source are contiguous in memory.
+     */
     U32    const matchLowest = isDictionary ? lowestValid : withinWindow;
     return matchLowest;
 }
@@ -1045,7 +1283,6 @@ MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max)
  * assumptions : magic number supposed already checked
  *               and dictSize >= 8 */
 size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
-                         short* offcodeNCount, unsigned* offcodeMaxValue,
                          const void* const dict, size_t dictSize);
 
 void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs);
@@ -1061,7 +1298,7 @@ void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs);
  * Note: srcSizeHint == 0 means 0!
  */
 ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
-        const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize);
+        const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode);
 
 /*! ZSTD_initCStream_internal() :
  *  Private use only. Init streaming operation.
@@ -1122,4 +1359,9 @@ size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSe
  *  condition for correct operation : hashLog > 1 */
 U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat);
 
+/** ZSTD_CCtx_trace() :
+ *  Trace the end of a compression call.
+ */
+void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize);
+
 #endif /* ZSTD_COMPRESS_H */
index 17e7168..008337b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -15,7 +15,7 @@
 
 size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
 {
-    BYTE* const ostart = (BYTE* const)dst;
+    BYTE* const ostart = (BYTE*)dst;
     U32   const flSize = 1 + (srcSize>31) + (srcSize>4095);
 
     RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall, "");
@@ -35,14 +35,14 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src,
             assert(0);
     }
 
-    memcpy(ostart + flSize, src, srcSize);
+    ZSTD_memcpy(ostart + flSize, src, srcSize);
     DEBUGLOG(5, "Raw literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize));
     return srcSize + flSize;
 }
 
 size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
 {
-    BYTE* const ostart = (BYTE* const)dst;
+    BYTE* const ostart = (BYTE*)dst;
     U32   const flSize = 1 + (srcSize>31) + (srcSize>4095);
 
     (void)dstCapacity;  /* dstCapacity already guaranteed to be >=4, hence large enough */
@@ -86,7 +86,7 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
                 disableLiteralCompression, (U32)srcSize);
 
     /* Prepare nextEntropy assuming reusing the existing table */
-    memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+    ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
 
     if (disableLiteralCompression)
         return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
@@ -117,12 +117,12 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
         }
     }
 
-    if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
-        memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+    if ((cLitSize==0) || (cLitSize >= srcSize - minGain) || ERR_isError(cLitSize)) {
+        ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
         return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
     }
     if (cLitSize==1) {
-        memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
+        ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
         return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
     }
 
index 8b08705..9904c0c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
index f9f8097..611eabd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -51,6 +51,19 @@ static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) {
 }
 
 /**
+ * Returns true if we should use ncount=-1 else we should
+ * use ncount=1 for low probability symbols instead.
+ */
+static unsigned ZSTD_useLowProbCount(size_t const nbSeq)
+{
+    /* Heuristic: This should cover most blocks <= 16K and
+     * start to fade out after 16K to about 32K depending on
+     * comprssibility.
+     */
+    return nbSeq >= 2048;
+}
+
+/**
  * Returns the cost in bytes of encoding the normalized count header.
  * Returns an error if any of the helper functions return an error.
  */
@@ -60,7 +73,7 @@ static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max,
     BYTE wksp[FSE_NCOUNTBOUND];
     S16 norm[MaxSeq + 1];
     const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
-    FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max), "");
+    FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max, ZSTD_useLowProbCount(nbSeq)), "");
     return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog);
 }
 
@@ -72,6 +85,8 @@ static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t
 {
     unsigned cost = 0;
     unsigned s;
+
+    assert(total > 0);
     for (s = 0; s <= max; ++s) {
         unsigned norm = (unsigned)((256 * count[s]) / total);
         if (count[s] != 0 && norm == 0)
@@ -219,6 +234,11 @@ ZSTD_selectEncodingType(
     return set_compressed;
 }
 
+typedef struct {
+    S16 norm[MaxSeq + 1];
+    U32 wksp[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(MaxSeq, MaxFSELog)];
+} ZSTD_BuildCTableWksp;
+
 size_t
 ZSTD_buildCTable(void* dst, size_t dstCapacity,
                 FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
@@ -239,13 +259,13 @@ ZSTD_buildCTable(void* dst, size_t dstCapacity,
         *op = codeTable[0];
         return 1;
     case set_repeat:
-        memcpy(nextCTable, prevCTable, prevCTableSize);
+        ZSTD_memcpy(nextCTable, prevCTable, prevCTableSize);
         return 0;
     case set_basic:
         FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, entropyWorkspace, entropyWorkspaceSize), "");  /* note : could be pre-calculated */
         return 0;
     case set_compressed: {
-        S16 norm[MaxSeq + 1];
+        ZSTD_BuildCTableWksp* wksp = (ZSTD_BuildCTableWksp*)entropyWorkspace;
         size_t nbSeq_1 = nbSeq;
         const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
         if (count[codeTable[nbSeq-1]] > 1) {
@@ -253,10 +273,12 @@ ZSTD_buildCTable(void* dst, size_t dstCapacity,
             nbSeq_1--;
         }
         assert(nbSeq_1 > 1);
-        FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max), "");
-        {   size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog);   /* overflow protected */
+        assert(entropyWorkspaceSize >= sizeof(ZSTD_BuildCTableWksp));
+        (void)entropyWorkspaceSize;
+        FORWARD_IF_ERROR(FSE_normalizeCount(wksp->norm, tableLog, count, nbSeq_1, max, ZSTD_useLowProbCount(nbSeq_1)), "");
+        {   size_t const NCountSize = FSE_writeNCount(op, oend - op, wksp->norm, max, tableLog);   /* overflow protected */
             FORWARD_IF_ERROR(NCountSize, "FSE_writeNCount failed");
-            FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, entropyWorkspace, entropyWorkspaceSize), "");
+            FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, wksp->norm, max, tableLog, wksp->wksp, sizeof(wksp->wksp)), "");
             return NCountSize;
         }
     }
index 68c6f9a..7991364 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
index b693866..e4e4506 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
 
 #include "../common/zstd_internal.h"  /* ZSTD_getSequenceLength */
 #include "hist.h"                     /* HIST_countFast_wksp */
-#include "zstd_compress_internal.h"
+#include "zstd_compress_internal.h"   /* ZSTD_[huf|fse|entropy]CTablesMetadata_t */
 #include "zstd_compress_sequences.h"
 #include "zstd_compress_literals.h"
 
-/*-*************************************
-*  Superblock entropy buffer structs
-***************************************/
-/** ZSTD_hufCTablesMetadata_t :
- *  Stores Literals Block Type for a super-block in hType, and
- *  huffman tree description in hufDesBuffer.
- *  hufDesSize refers to the size of huffman tree description in bytes.
- *  This metadata is populated in ZSTD_buildSuperBlockEntropy_literal() */
-typedef struct {
-    symbolEncodingType_e hType;
-    BYTE hufDesBuffer[500]; /* TODO give name to this value */
-    size_t hufDesSize;
-} ZSTD_hufCTablesMetadata_t;
-
-/** ZSTD_fseCTablesMetadata_t :
- *  Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and
- *  fse tables in fseTablesBuffer.
- *  fseTablesSize refers to the size of fse tables in bytes.
- *  This metadata is populated in ZSTD_buildSuperBlockEntropy_sequences() */
-typedef struct {
-    symbolEncodingType_e llType;
-    symbolEncodingType_e ofType;
-    symbolEncodingType_e mlType;
-    BYTE fseTablesBuffer[500]; /* TODO give name to this value */
-    size_t fseTablesSize;
-    size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_compressSubBlock_sequences() */
-} ZSTD_fseCTablesMetadata_t;
-
-typedef struct {
-    ZSTD_hufCTablesMetadata_t hufMetadata;
-    ZSTD_fseCTablesMetadata_t fseMetadata;
-} ZSTD_entropyCTablesMetadata_t;
-
-
-/** ZSTD_buildSuperBlockEntropy_literal() :
- *  Builds entropy for the super-block literals.
- *  Stores literals block type (raw, rle, compressed, repeat) and
- *  huffman description table to hufMetadata.
- *  @return : size of huffman description table or error code */
-static size_t ZSTD_buildSuperBlockEntropy_literal(void* const src, size_t srcSize,
-                                            const ZSTD_hufCTables_t* prevHuf,
-                                                  ZSTD_hufCTables_t* nextHuf,
-                                                  ZSTD_hufCTablesMetadata_t* hufMetadata,
-                                                  const int disableLiteralsCompression,
-                                                  void* workspace, size_t wkspSize)
-{
-    BYTE* const wkspStart = (BYTE*)workspace;
-    BYTE* const wkspEnd = wkspStart + wkspSize;
-    BYTE* const countWkspStart = wkspStart;
-    unsigned* const countWksp = (unsigned*)workspace;
-    const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned);
-    BYTE* const nodeWksp = countWkspStart + countWkspSize;
-    const size_t nodeWkspSize = wkspEnd-nodeWksp;
-    unsigned maxSymbolValue = 255;
-    unsigned huffLog = HUF_TABLELOG_DEFAULT;
-    HUF_repeat repeat = prevHuf->repeatMode;
-
-    DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_literal (srcSize=%zu)", srcSize);
-
-    /* Prepare nextEntropy assuming reusing the existing table */
-    memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
-
-    if (disableLiteralsCompression) {
-        DEBUGLOG(5, "set_basic - disabled");
-        hufMetadata->hType = set_basic;
-        return 0;
-    }
-
-    /* small ? don't even attempt compression (speed opt) */
-#   define COMPRESS_LITERALS_SIZE_MIN 63
-    {   size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
-        if (srcSize <= minLitSize) {
-            DEBUGLOG(5, "set_basic - too small");
-            hufMetadata->hType = set_basic;
-            return 0;
-        }
-    }
-
-    /* Scan input and build symbol stats */
-    {   size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)src, srcSize, workspace, wkspSize);
-        FORWARD_IF_ERROR(largest, "HIST_count_wksp failed");
-        if (largest == srcSize) {
-            DEBUGLOG(5, "set_rle");
-            hufMetadata->hType = set_rle;
-            return 0;
-        }
-        if (largest <= (srcSize >> 7)+4) {
-            DEBUGLOG(5, "set_basic - no gain");
-            hufMetadata->hType = set_basic;
-            return 0;
-        }
-    }
-
-    /* Validate the previous Huffman table */
-    if (repeat == HUF_repeat_check && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) {
-        repeat = HUF_repeat_none;
-    }
-
-    /* Build Huffman Tree */
-    memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable));
-    huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
-    {   size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp,
-                                                    maxSymbolValue, huffLog,
-                                                    nodeWksp, nodeWkspSize);
-        FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp");
-        huffLog = (U32)maxBits;
-        {   /* Build and write the CTable */
-            size_t const newCSize = HUF_estimateCompressedSize(
-                    (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue);
-            size_t const hSize = HUF_writeCTable(
-                    hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer),
-                    (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog);
-            /* Check against repeating the previous CTable */
-            if (repeat != HUF_repeat_none) {
-                size_t const oldCSize = HUF_estimateCompressedSize(
-                        (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue);
-                if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) {
-                    DEBUGLOG(5, "set_repeat - smaller");
-                    memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
-                    hufMetadata->hType = set_repeat;
-                    return 0;
-                }
-            }
-            if (newCSize + hSize >= srcSize) {
-                DEBUGLOG(5, "set_basic - no gains");
-                memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
-                hufMetadata->hType = set_basic;
-                return 0;
-            }
-            DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize);
-            hufMetadata->hType = set_compressed;
-            nextHuf->repeatMode = HUF_repeat_check;
-            return hSize;
-        }
-    }
-}
-
-/** ZSTD_buildSuperBlockEntropy_sequences() :
- *  Builds entropy for the super-block sequences.
- *  Stores symbol compression modes and fse table to fseMetadata.
- *  @return : size of fse tables or error code */
-static size_t ZSTD_buildSuperBlockEntropy_sequences(seqStore_t* seqStorePtr,
-                                              const ZSTD_fseCTables_t* prevEntropy,
-                                                    ZSTD_fseCTables_t* nextEntropy,
-                                              const ZSTD_CCtx_params* cctxParams,
-                                                    ZSTD_fseCTablesMetadata_t* fseMetadata,
-                                                    void* workspace, size_t wkspSize)
-{
-    BYTE* const wkspStart = (BYTE*)workspace;
-    BYTE* const wkspEnd = wkspStart + wkspSize;
-    BYTE* const countWkspStart = wkspStart;
-    unsigned* const countWksp = (unsigned*)workspace;
-    const size_t countWkspSize = (MaxSeq + 1) * sizeof(unsigned);
-    BYTE* const cTableWksp = countWkspStart + countWkspSize;
-    const size_t cTableWkspSize = wkspEnd-cTableWksp;
-    ZSTD_strategy const strategy = cctxParams->cParams.strategy;
-    FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable;
-    FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable;
-    FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable;
-    const BYTE* const ofCodeTable = seqStorePtr->ofCode;
-    const BYTE* const llCodeTable = seqStorePtr->llCode;
-    const BYTE* const mlCodeTable = seqStorePtr->mlCode;
-    size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
-    BYTE* const ostart = fseMetadata->fseTablesBuffer;
-    BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer);
-    BYTE* op = ostart;
-
-    assert(cTableWkspSize >= (1 << MaxFSELog) * sizeof(FSE_FUNCTION_TYPE));
-    DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_sequences (nbSeq=%zu)", nbSeq);
-    memset(workspace, 0, wkspSize);
-
-    fseMetadata->lastCountSize = 0;
-    /* convert length/distances into codes */
-    ZSTD_seqToCodes(seqStorePtr);
-    /* build CTable for Literal Lengths */
-    {   U32 LLtype;
-        unsigned max = MaxLL;
-        size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, llCodeTable, nbSeq, workspace, wkspSize);  /* can't fail */
-        DEBUGLOG(5, "Building LL table");
-        nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
-        LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode,
-                                        countWksp, max, mostFrequent, nbSeq,
-                                        LLFSELog, prevEntropy->litlengthCTable,
-                                        LL_defaultNorm, LL_defaultNormLog,
-                                        ZSTD_defaultAllowed, strategy);
-        assert(set_basic < set_compressed && set_rle < set_compressed);
-        assert(!(LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
-        {   size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
-                                                    countWksp, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
-                                                    prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable),
-                                                    cTableWksp, cTableWkspSize);
-            FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed");
-            if (LLtype == set_compressed)
-                fseMetadata->lastCountSize = countSize;
-            op += countSize;
-            fseMetadata->llType = (symbolEncodingType_e) LLtype;
-    }   }
-    /* build CTable for Offsets */
-    {   U32 Offtype;
-        unsigned max = MaxOff;
-        size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, ofCodeTable, nbSeq, workspace, wkspSize);  /* can't fail */
-        /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
-        ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
-        DEBUGLOG(5, "Building OF table");
-        nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
-        Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode,
-                                        countWksp, max, mostFrequent, nbSeq,
-                                        OffFSELog, prevEntropy->offcodeCTable,
-                                        OF_defaultNorm, OF_defaultNormLog,
-                                        defaultPolicy, strategy);
-        assert(!(Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
-        {   size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
-                                                    countWksp, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
-                                                    prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable),
-                                                    cTableWksp, cTableWkspSize);
-            FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed");
-            if (Offtype == set_compressed)
-                fseMetadata->lastCountSize = countSize;
-            op += countSize;
-            fseMetadata->ofType = (symbolEncodingType_e) Offtype;
-    }   }
-    /* build CTable for MatchLengths */
-    {   U32 MLtype;
-        unsigned max = MaxML;
-        size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, mlCodeTable, nbSeq, workspace, wkspSize);   /* can't fail */
-        DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
-        nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
-        MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode,
-                                        countWksp, max, mostFrequent, nbSeq,
-                                        MLFSELog, prevEntropy->matchlengthCTable,
-                                        ML_defaultNorm, ML_defaultNormLog,
-                                        ZSTD_defaultAllowed, strategy);
-        assert(!(MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
-        {   size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
-                                                    countWksp, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
-                                                    prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable),
-                                                    cTableWksp, cTableWkspSize);
-            FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed");
-            if (MLtype == set_compressed)
-                fseMetadata->lastCountSize = countSize;
-            op += countSize;
-            fseMetadata->mlType = (symbolEncodingType_e) MLtype;
-    }   }
-    assert((size_t) (op-ostart) <= sizeof(fseMetadata->fseTablesBuffer));
-    return op-ostart;
-}
-
-
-/** ZSTD_buildSuperBlockEntropy() :
- *  Builds entropy for the super-block.
- *  @return : 0 on success or error code */
-static size_t
-ZSTD_buildSuperBlockEntropy(seqStore_t* seqStorePtr,
-                      const ZSTD_entropyCTables_t* prevEntropy,
-                            ZSTD_entropyCTables_t* nextEntropy,
-                      const ZSTD_CCtx_params* cctxParams,
-                            ZSTD_entropyCTablesMetadata_t* entropyMetadata,
-                            void* workspace, size_t wkspSize)
-{
-    size_t const litSize = seqStorePtr->lit - seqStorePtr->litStart;
-    DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy");
-    entropyMetadata->hufMetadata.hufDesSize =
-        ZSTD_buildSuperBlockEntropy_literal(seqStorePtr->litStart, litSize,
-                                            &prevEntropy->huf, &nextEntropy->huf,
-                                            &entropyMetadata->hufMetadata,
-                                            ZSTD_disableLiteralsCompression(cctxParams),
-                                            workspace, wkspSize);
-    FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildSuperBlockEntropy_literal failed");
-    entropyMetadata->fseMetadata.fseTablesSize =
-        ZSTD_buildSuperBlockEntropy_sequences(seqStorePtr,
-                                              &prevEntropy->fse, &nextEntropy->fse,
-                                              cctxParams,
-                                              &entropyMetadata->fseMetadata,
-                                              workspace, wkspSize);
-    FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildSuperBlockEntropy_sequences failed");
-    return 0;
-}
-
 /** ZSTD_compressSubBlock_literal() :
  *  Compresses literals section for a sub-block.
  *  When we have to write the Huffman table we will sometimes choose a header
@@ -304,7 +26,7 @@ ZSTD_buildSuperBlockEntropy(seqStore_t* seqStorePtr,
  *  before we know the table size + compressed size, so we have a bound on the
  *  table size. If we guessed incorrectly, we fall back to uncompressed literals.
  *
- *  We write the header when writeEntropy=1 and set entropyWrriten=1 when we succeeded
+ *  We write the header when writeEntropy=1 and set entropyWritten=1 when we succeeded
  *  in writing the header, otherwise it is set to 0.
  *
  *  hufMetadata->hType has literals block type info.
@@ -348,7 +70,7 @@ static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
     assert(hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat);
 
     if (writeEntropy && hufMetadata->hType == set_compressed) {
-        memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize);
+        ZSTD_memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize);
         op += hufMetadata->hufDesSize;
         cLitSize += hufMetadata->hufDesSize;
         DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize);
@@ -474,7 +196,7 @@ static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables
         const U32 MLtype = fseMetadata->mlType;
         DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (fseTablesSize=%zu)", fseMetadata->fseTablesSize);
         *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
-        memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize);
+        ZSTD_memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize);
         op += fseMetadata->fseTablesSize;
     } else {
         const U32 repeat = set_repeat;
@@ -603,7 +325,7 @@ static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type,
                         const BYTE* codeTable, unsigned maxCode,
                         size_t nbSeq, const FSE_CTable* fseCTable,
                         const U32* additionalBits,
-                        short const* defaultNorm, U32 defaultNormLog,
+                        short const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
                         void* workspace, size_t wkspSize)
 {
     unsigned* const countWksp = (unsigned*)workspace;
@@ -615,7 +337,11 @@ static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type,
 
     HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize);  /* can't fail */
     if (type == set_basic) {
-        cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max);
+        /* We selected this encoding type, so it must be valid. */
+        assert(max <= defaultMax);
+        cSymbolTypeSizeEstimateInBits = max <= defaultMax
+                ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max)
+                : ERROR(GENERIC);
     } else if (type == set_rle) {
         cSymbolTypeSizeEstimateInBits = 0;
     } else if (type == set_compressed || type == set_repeat) {
@@ -639,19 +365,20 @@ static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable,
                                                   void* workspace, size_t wkspSize,
                                                   int writeEntropy)
 {
-    size_t sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */
+    size_t const sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */
     size_t cSeqSizeEstimate = 0;
+    if (nbSeq == 0) return sequencesSectionHeaderSize;
     cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff,
                                          nbSeq, fseTables->offcodeCTable, NULL,
-                                         OF_defaultNorm, OF_defaultNormLog,
+                                         OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
                                          workspace, wkspSize);
     cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->llType, llCodeTable, MaxLL,
                                          nbSeq, fseTables->litlengthCTable, LL_bits,
-                                         LL_defaultNorm, LL_defaultNormLog,
+                                         LL_defaultNorm, LL_defaultNormLog, MaxLL,
                                          workspace, wkspSize);
     cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, MaxML,
                                          nbSeq, fseTables->matchlengthCTable, ML_bits,
-                                         ML_defaultNorm, ML_defaultNormLog,
+                                         ML_defaultNorm, ML_defaultNormLog, MaxML,
                                          workspace, wkspSize);
     if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize;
     return cSeqSizeEstimate + sequencesSectionHeaderSize;
@@ -790,7 +517,7 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
     } while (!lastSequence);
     if (writeLitEntropy) {
         DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten");
-        memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf));
+        ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf));
     }
     if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) {
         /* If we haven't written our entropy tables, then we've violated our contract and
@@ -809,11 +536,11 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
         if (sp < send) {
             seqDef const* seq;
             repcodes_t rep;
-            memcpy(&rep, prevCBlock->rep, sizeof(rep)); 
+            ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep));
             for (seq = sstart; seq < sp; ++seq) {
                 rep = ZSTD_updateRep(rep.rep, seq->offset - 1, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0);
             }
-            memcpy(nextCBlock->rep, &rep, sizeof(rep));
+            ZSTD_memcpy(nextCBlock->rep, &rep, sizeof(rep));
         }
     }
     DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed");
@@ -826,12 +553,12 @@ size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
                                unsigned lastBlock) {
     ZSTD_entropyCTablesMetadata_t entropyMetadata;
 
-    FORWARD_IF_ERROR(ZSTD_buildSuperBlockEntropy(&zc->seqStore,
+    FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore,
           &zc->blockState.prevCBlock->entropy,
           &zc->blockState.nextCBlock->entropy,
           &zc->appliedParams,
           &entropyMetadata,
-          zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */), "");
+          zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), "");
 
     return ZSTD_compressSubBlock_multi(&zc->seqStore,
             zc->blockState.prevCBlock,
@@ -841,5 +568,5 @@ size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
             dst, dstCapacity,
             src, srcSize,
             zc->bmi2, lastBlock,
-            zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */);
+            zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */);
 }
index 07f4cb1..176f9b1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
index a25c926..2656d26 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -35,6 +35,10 @@ extern "C" {
 #define ZSTD_CWKSP_ASAN_REDZONE_SIZE 128
 #endif
 
+
+/* Set our tables and aligneds to align by 64 bytes */
+#define ZSTD_CWKSP_ALIGNMENT_BYTES 64
+
 /*-*************************************
 *  Structures
 ***************************************/
@@ -45,6 +49,16 @@ typedef enum {
 } ZSTD_cwksp_alloc_phase_e;
 
 /**
+ * Used to describe whether the workspace is statically allocated (and will not
+ * necessarily ever be freed), or if it's dynamically allocated and we can
+ * expect a well-formed caller to free this.
+ */
+typedef enum {
+    ZSTD_cwksp_dynamic_alloc,
+    ZSTD_cwksp_static_alloc
+} ZSTD_cwksp_static_alloc_e;
+
+/**
  * Zstd fits all its internal datastructures into a single continuous buffer,
  * so that it only needs to perform a single OS allocation (or so that a buffer
  * can be provided to it and it can perform no allocations at all). This buffer
@@ -92,7 +106,7 @@ typedef enum {
  *
  * - Static objects: this is optionally the enclosing ZSTD_CCtx or ZSTD_CDict,
  *   so that literally everything fits in a single buffer. Note: if present,
- *   this must be the first object in the workspace, since ZSTD_free{CCtx,
+ *   this must be the first object in the workspace, since ZSTD_customFree{CCtx,
  *   CDict}() rely on a pointer comparison to see whether one or two frees are
  *   required.
  *
@@ -107,10 +121,11 @@ typedef enum {
  * - Tables: these are any of several different datastructures (hash tables,
  *   chain tables, binary trees) that all respect a common format: they are
  *   uint32_t arrays, all of whose values are between 0 and (nextSrc - base).
- *   Their sizes depend on the cparams.
+ *   Their sizes depend on the cparams. These tables are 64-byte aligned.
  *
  * - Aligned: these buffers are used for various purposes that require 4 byte
- *   alignment, but don't require any initialization before they're used.
+ *   alignment, but don't require any initialization before they're used. These
+ *   buffers are each aligned to 64 bytes.
  *
  * - Buffers: these buffers are used for various purposes that don't require
  *   any alignment or initialization before they're used. This means they can
@@ -123,8 +138,7 @@ typedef enum {
  *
  * 1. Objects
  * 2. Buffers
- * 3. Aligned
- * 4. Tables
+ * 3. Aligned/Tables
  *
  * Attempts to reserve objects of different types out of order will fail.
  */
@@ -137,9 +151,10 @@ typedef struct {
     void* tableValidEnd;
     void* allocStart;
 
-    int allocFailed;
+    BYTE allocFailed;
     int workspaceOversizedDuration;
     ZSTD_cwksp_alloc_phase_e phase;
+    ZSTD_cwksp_static_alloc_e isStatic;
 } ZSTD_cwksp;
 
 /*-*************************************
@@ -176,39 +191,123 @@ MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) {
  * Since tables aren't currently redzoned, you don't need to call through this
  * to figure out how much space you need for the matchState tables. Everything
  * else is though.
+ *
+ * Do not use for sizing aligned buffers. Instead, use ZSTD_cwksp_aligned_alloc_size().
  */
 MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+    if (size == 0)
+        return 0;
+#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
     return size + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
 #else
     return size;
 #endif
 }
 
-MEM_STATIC void ZSTD_cwksp_internal_advance_phase(
+/**
+ * Returns an adjusted alloc size that is the nearest larger multiple of 64 bytes.
+ * Used to determine the number of bytes required for a given "aligned".
+ */
+MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size) {
+    return ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(size, ZSTD_CWKSP_ALIGNMENT_BYTES));
+}
+
+/**
+ * Returns the amount of additional space the cwksp must allocate
+ * for internal purposes (currently only alignment).
+ */
+MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) {
+    /* For alignment, the wksp will always allocate an additional n_1=[1, 64] bytes
+     * to align the beginning of tables section, as well as another n_2=[0, 63] bytes
+     * to align the beginning of the aligned secion.
+     *
+     * n_1 + n_2 == 64 bytes if the cwksp is freshly allocated, due to tables and
+     * aligneds being sized in multiples of 64 bytes.
+     */
+    size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES;
+    return slackSpace;
+}
+
+
+/**
+ * Return the number of additional bytes required to align a pointer to the given number of bytes.
+ * alignBytes must be a power of two.
+ */
+MEM_STATIC size_t ZSTD_cwksp_bytes_to_align_ptr(void* ptr, const size_t alignBytes) {
+    size_t const alignBytesMask = alignBytes - 1;
+    size_t const bytes = (alignBytes - ((size_t)ptr & (alignBytesMask))) & alignBytesMask;
+    assert((alignBytes & alignBytesMask) == 0);
+    assert(bytes != ZSTD_CWKSP_ALIGNMENT_BYTES);
+    return bytes;
+}
+
+/**
+ * Internal function. Do not use directly.
+ * Reserves the given number of bytes within the aligned/buffer segment of the wksp, which
+ * counts from the end of the wksp. (as opposed to the object/table segment)
+ *
+ * Returns a pointer to the beginning of that space.
+ */
+MEM_STATIC void* ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes) {
+    void* const alloc = (BYTE*)ws->allocStart - bytes;
+    void* const bottom = ws->tableEnd;
+    DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining",
+        alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
+    ZSTD_cwksp_assert_internal_consistency(ws);
+    assert(alloc >= bottom);
+    if (alloc < bottom) {
+        DEBUGLOG(4, "cwksp: alloc failed!");
+        ws->allocFailed = 1;
+        return NULL;
+    }
+    if (alloc < ws->tableValidEnd) {
+        ws->tableValidEnd = alloc;
+    }
+    ws->allocStart = alloc;
+    return alloc;
+}
+
+/**
+ * Moves the cwksp to the next phase, and does any necessary allocations.
+ * Returns a 0 on success, or zstd error
+ */
+MEM_STATIC size_t ZSTD_cwksp_internal_advance_phase(
         ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) {
     assert(phase >= ws->phase);
     if (phase > ws->phase) {
+        /* Going from allocating objects to allocating buffers */
         if (ws->phase < ZSTD_cwksp_alloc_buffers &&
                 phase >= ZSTD_cwksp_alloc_buffers) {
             ws->tableValidEnd = ws->objectEnd;
         }
+
+        /* Going from allocating buffers to allocating aligneds/tables */
         if (ws->phase < ZSTD_cwksp_alloc_aligned &&
                 phase >= ZSTD_cwksp_alloc_aligned) {
-            /* If unaligned allocations down from a too-large top have left us
-             * unaligned, we need to realign our alloc ptr. Technically, this
-             * can consume space that is unaccounted for in the neededSpace
-             * calculation. However, I believe this can only happen when the
-             * workspace is too large, and specifically when it is too large
-             * by a larger margin than the space that will be consumed. */
-            /* TODO: cleaner, compiler warning friendly way to do this??? */
-            ws->allocStart = (BYTE*)ws->allocStart - ((size_t)ws->allocStart & (sizeof(U32)-1));
-            if (ws->allocStart < ws->tableValidEnd) {
-                ws->tableValidEnd = ws->allocStart;
+            {   /* Align the start of the "aligned" to 64 bytes. Use [1, 64] bytes. */
+                size_t const bytesToAlign =
+                    ZSTD_CWKSP_ALIGNMENT_BYTES - ZSTD_cwksp_bytes_to_align_ptr(ws->allocStart, ZSTD_CWKSP_ALIGNMENT_BYTES);
+                DEBUGLOG(5, "reserving aligned alignment addtl space: %zu", bytesToAlign);
+                ZSTD_STATIC_ASSERT((ZSTD_CWKSP_ALIGNMENT_BYTES & (ZSTD_CWKSP_ALIGNMENT_BYTES - 1)) == 0); /* power of 2 */
+                RETURN_ERROR_IF(!ZSTD_cwksp_reserve_internal_buffer_space(ws, bytesToAlign),
+                                memory_allocation, "aligned phase - alignment initial allocation failed!");
+            }
+            {   /* Align the start of the tables to 64 bytes. Use [0, 63] bytes */
+                void* const alloc = ws->objectEnd;
+                size_t const bytesToAlign = ZSTD_cwksp_bytes_to_align_ptr(alloc, ZSTD_CWKSP_ALIGNMENT_BYTES);
+                void* const end = (BYTE*)alloc + bytesToAlign;
+                DEBUGLOG(5, "reserving table alignment addtl space: %zu", bytesToAlign);
+                RETURN_ERROR_IF(end > ws->workspaceEnd, memory_allocation,
+                                "table phase - alignment initial allocation failed!");
+                ws->objectEnd = end;
+                ws->tableEnd = end;
+                ws->tableValidEnd = end;
             }
         }
         ws->phase = phase;
+        ZSTD_cwksp_assert_internal_consistency(ws);
     }
+    return 0;
 }
 
 /**
@@ -224,34 +323,26 @@ MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) {
 MEM_STATIC void* ZSTD_cwksp_reserve_internal(
         ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) {
     void* alloc;
-    void* bottom = ws->tableEnd;
-    ZSTD_cwksp_internal_advance_phase(ws, phase);
-    alloc = (BYTE *)ws->allocStart - bytes;
+    if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase)) || bytes == 0) {
+        return NULL;
+    }
 
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
     /* over-reserve space */
-    alloc = (BYTE *)alloc - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
+    bytes += 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
 #endif
 
-    DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining",
-        alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
-    ZSTD_cwksp_assert_internal_consistency(ws);
-    assert(alloc >= bottom);
-    if (alloc < bottom) {
-        DEBUGLOG(4, "cwksp: alloc failed!");
-        ws->allocFailed = 1;
-        return NULL;
-    }
-    if (alloc < ws->tableValidEnd) {
-        ws->tableValidEnd = alloc;
-    }
-    ws->allocStart = alloc;
+    alloc = ZSTD_cwksp_reserve_internal_buffer_space(ws, bytes);
 
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
     /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
      * either size. */
-    alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
-    __asan_unpoison_memory_region(alloc, bytes);
+    if (alloc) {
+        alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
+        if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
+            __asan_unpoison_memory_region(alloc, bytes);
+        }
+    }
 #endif
 
     return alloc;
@@ -265,28 +356,36 @@ MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) {
 }
 
 /**
- * Reserves and returns memory sized on and aligned on sizeof(unsigned).
+ * Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes).
  */
 MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) {
-    assert((bytes & (sizeof(U32)-1)) == 0);
-    return ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, sizeof(U32)), ZSTD_cwksp_alloc_aligned);
+    void* ptr = ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES),
+                                            ZSTD_cwksp_alloc_aligned);
+    assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
+    return ptr;
 }
 
 /**
- * Aligned on sizeof(unsigned). These buffers have the special property that
+ * Aligned on 64 bytes. These buffers have the special property that
  * their values remain constrained, allowing us to re-use them without
  * memset()-ing them.
  */
 MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
     const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned;
-    void* alloc = ws->tableEnd;
-    void* end = (BYTE *)alloc + bytes;
-    void* top = ws->allocStart;
+    void* alloc;
+    void* end;
+    void* top;
+
+    if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) {
+        return NULL;
+    }
+    alloc = ws->tableEnd;
+    end = (BYTE *)alloc + bytes;
+    top = ws->allocStart;
 
     DEBUGLOG(5, "cwksp: reserving %p table %zd bytes, %zd bytes remaining",
         alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
     assert((bytes & (sizeof(U32)-1)) == 0);
-    ZSTD_cwksp_internal_advance_phase(ws, phase);
     ZSTD_cwksp_assert_internal_consistency(ws);
     assert(end <= top);
     if (end > top) {
@@ -296,10 +395,14 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
     }
     ws->tableEnd = end;
 
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
-    __asan_unpoison_memory_region(alloc, bytes);
+#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+    if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
+        __asan_unpoison_memory_region(alloc, bytes);
+    }
 #endif
 
+    assert((bytes & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0);
+    assert(((size_t)alloc & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
     return alloc;
 }
 
@@ -311,7 +414,7 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
     void* alloc = ws->objectEnd;
     void* end = (BYTE*)alloc + roundedBytes;
 
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
     /* over-reserve space */
     end = (BYTE *)end + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
 #endif
@@ -332,11 +435,13 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
     ws->tableEnd = end;
     ws->tableValidEnd = end;
 
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
     /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
      * either size. */
     alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
-    __asan_unpoison_memory_region(alloc, bytes);
+    if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
+        __asan_unpoison_memory_region(alloc, bytes);
+    }
 #endif
 
     return alloc;
@@ -345,7 +450,7 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
 MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) {
     DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_dirty");
 
-#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
+#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
     /* To validate that the table re-use logic is sound, and that we don't
      * access table space that we haven't cleaned, we re-"poison" the table
      * space every time we mark it dirty. */
@@ -380,7 +485,7 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) {
     assert(ws->tableValidEnd >= ws->objectEnd);
     assert(ws->tableValidEnd <= ws->allocStart);
     if (ws->tableValidEnd < ws->tableEnd) {
-        memset(ws->tableValidEnd, 0, (BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd);
+        ZSTD_memset(ws->tableValidEnd, 0, (BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd);
     }
     ZSTD_cwksp_mark_tables_clean(ws);
 }
@@ -392,8 +497,12 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) {
 MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) {
     DEBUGLOG(4, "cwksp: clearing tables!");
 
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
-    {
+#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+    /* We don't do this when the workspace is statically allocated, because
+     * when that is the case, we have no capability to hook into the end of the
+     * workspace's lifecycle to unpoison the memory.
+     */
+    if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
         size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd;
         __asan_poison_memory_region(ws->objectEnd, size);
     }
@@ -410,7 +519,7 @@ MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) {
 MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
     DEBUGLOG(4, "cwksp: clearing!");
 
-#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
+#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
     /* To validate that the context re-use logic is sound, and that we don't
      * access stuff that this compression hasn't initialized, we re-"poison"
      * the workspace (or at least the non-static, non-table parts of it)
@@ -421,8 +530,12 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
     }
 #endif
 
-#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
-    {
+#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
+    /* We don't do this when the workspace is statically allocated, because
+     * when that is the case, we have no capability to hook into the end of the
+     * workspace's lifecycle to unpoison the memory.
+     */
+    if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
         size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->objectEnd;
         __asan_poison_memory_region(ws->objectEnd, size);
     }
@@ -442,7 +555,7 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
  * Any existing values in the workspace are ignored (the previously managed
  * buffer, if present, must be separately freed).
  */
-MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size) {
+MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size, ZSTD_cwksp_static_alloc_e isStatic) {
     DEBUGLOG(4, "cwksp: init'ing workspace with %zd bytes", size);
     assert(((size_t)start & (sizeof(void*)-1)) == 0); /* ensure correct alignment */
     ws->workspace = start;
@@ -450,39 +563,45 @@ MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size) {
     ws->objectEnd = ws->workspace;
     ws->tableValidEnd = ws->objectEnd;
     ws->phase = ZSTD_cwksp_alloc_objects;
+    ws->isStatic = isStatic;
     ZSTD_cwksp_clear(ws);
     ws->workspaceOversizedDuration = 0;
     ZSTD_cwksp_assert_internal_consistency(ws);
 }
 
 MEM_STATIC size_t ZSTD_cwksp_create(ZSTD_cwksp* ws, size_t size, ZSTD_customMem customMem) {
-    void* workspace = ZSTD_malloc(size, customMem);
+    void* workspace = ZSTD_customMalloc(size, customMem);
     DEBUGLOG(4, "cwksp: creating new workspace with %zd bytes", size);
     RETURN_ERROR_IF(workspace == NULL, memory_allocation, "NULL pointer!");
-    ZSTD_cwksp_init(ws, workspace, size);
+    ZSTD_cwksp_init(ws, workspace, size, ZSTD_cwksp_dynamic_alloc);
     return 0;
 }
 
 MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) {
     void *ptr = ws->workspace;
     DEBUGLOG(4, "cwksp: freeing workspace");
-    memset(ws, 0, sizeof(ZSTD_cwksp));
-    ZSTD_free(ptr, customMem);
+    ZSTD_memset(ws, 0, sizeof(ZSTD_cwksp));
+    ZSTD_customFree(ptr, customMem);
 }
 
 /**
  * Moves the management of a workspace from one cwksp to another. The src cwksp
- * is left in an invalid state (src must be re-init()'ed before its used again).
+ * is left in an invalid state (src must be re-init()'ed before it's used again).
  */
 MEM_STATIC void ZSTD_cwksp_move(ZSTD_cwksp* dst, ZSTD_cwksp* src) {
     *dst = *src;
-    memset(src, 0, sizeof(ZSTD_cwksp));
+    ZSTD_memset(src, 0, sizeof(ZSTD_cwksp));
 }
 
 MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) {
     return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace);
 }
 
+MEM_STATIC size_t ZSTD_cwksp_used(const ZSTD_cwksp* ws) {
+    return (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->workspace)
+         + (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->allocStart);
+}
+
 MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
     return ws->allocFailed;
 }
@@ -491,6 +610,24 @@ MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
 *  Functions Checking Free Space
 ***************************************/
 
+/* ZSTD_alignmentSpaceWithinBounds() :
+ * Returns if the estimated space needed for a wksp is within an acceptable limit of the
+ * actual amount of space used.
+ */
+MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp* const ws,
+                                                        size_t const estimatedSpace, int resizedWorkspace) {
+    if (resizedWorkspace) {
+        /* Resized/newly allocated wksp should have exact bounds */
+        return ZSTD_cwksp_used(ws) == estimatedSpace;
+    } else {
+        /* Due to alignment, when reusing a workspace, we can actually consume 63 fewer or more bytes
+         * than estimatedSpace. See the comments in zstd_cwksp.h for details.
+         */
+        return (ZSTD_cwksp_used(ws) >= estimatedSpace - 63) && (ZSTD_cwksp_used(ws) <= estimatedSpace + 63);
+    }
+}
+
+
 MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws) {
     return (size_t)((BYTE*)ws->allocStart - (BYTE*)ws->tableEnd);
 }
index 27eed66..d0d3a78 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -31,15 +31,15 @@ void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
      * is empty.
      */
     for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) {
-        U32 const current = (U32)(ip - base);
+        U32 const curr = (U32)(ip - base);
         U32 i;
         for (i = 0; i < fastHashFillStep; ++i) {
             size_t const smHash = ZSTD_hashPtr(ip + i, hBitsS, mls);
             size_t const lgHash = ZSTD_hashPtr(ip + i, hBitsL, 8);
             if (i == 0)
-                hashSmall[smHash] = current + i;
+                hashSmall[smHash] = curr + i;
             if (i == 0 || hashLarge[lgHash] == 0)
-                hashLarge[lgHash] = current + i;
+                hashLarge[lgHash] = curr + i;
             /* Only load extra positions for ZSTD_dtlm_full */
             if (dtlm == ZSTD_dtlm_fast)
                 break;
@@ -108,9 +108,9 @@ size_t ZSTD_compressBlock_doubleFast_generic(
     /* init */
     ip += (dictAndPrefixLength == 0);
     if (dictMode == ZSTD_noDict) {
-        U32 const current = (U32)(ip - base);
-        U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog);
-        U32 const maxRep = current - windowLow;
+        U32 const curr = (U32)(ip - base);
+        U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, cParams->windowLog);
+        U32 const maxRep = curr - windowLow;
         if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
         if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
     }
@@ -129,17 +129,17 @@ size_t ZSTD_compressBlock_doubleFast_generic(
         size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
         size_t const dictHL = ZSTD_hashPtr(ip, dictHBitsL, 8);
         size_t const dictHS = ZSTD_hashPtr(ip, dictHBitsS, mls);
-        U32 const current = (U32)(ip-base);
+        U32 const curr = (U32)(ip-base);
         U32 const matchIndexL = hashLong[h2];
         U32 matchIndexS = hashSmall[h];
         const BYTE* matchLong = base + matchIndexL;
         const BYTE* match = base + matchIndexS;
-        const U32 repIndex = current + 1 - offset_1;
+        const U32 repIndex = curr + 1 - offset_1;
         const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
                             && repIndex < prefixLowestIndex) ?
                                dictBase + (repIndex - dictIndexDelta) :
                                base + repIndex;
-        hashLong[h2] = hashSmall[h] = current;   /* update hash tables */
+        hashLong[h2] = hashSmall[h] = curr;   /* update hash tables */
 
         /* check dictMatchState repcode */
         if (dictMode == ZSTD_dictMatchState
@@ -177,7 +177,7 @@ size_t ZSTD_compressBlock_doubleFast_generic(
 
             if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) {
                 mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8;
-                offset = (U32)(current - dictMatchIndexL - dictIndexDelta);
+                offset = (U32)(curr - dictMatchIndexL - dictIndexDelta);
                 while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */
                 goto _match_found;
         }   }
@@ -209,7 +209,7 @@ _search_next_long:
             size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8);
             U32 const matchIndexL3 = hashLong[hl3];
             const BYTE* matchL3 = base + matchIndexL3;
-            hashLong[hl3] = current + 1;
+            hashLong[hl3] = curr + 1;
 
             /* check prefix long +1 match */
             if (matchIndexL3 > prefixLowestIndex) {
@@ -228,7 +228,7 @@ _search_next_long:
                 if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) {
                     mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8;
                     ip++;
-                    offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta);
+                    offset = (U32)(curr + 1 - dictMatchIndexL3 - dictIndexDelta);
                     while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */
                     goto _match_found;
         }   }   }
@@ -236,7 +236,7 @@ _search_next_long:
         /* if no long +1 match, explore the short match we found */
         if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) {
             mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4;
-            offset = (U32)(current - matchIndexS);
+            offset = (U32)(curr - matchIndexS);
             while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
         } else {
             mLength = ZSTD_count(ip+4, match+4, iend) + 4;
@@ -260,7 +260,7 @@ _match_stored:
         if (ip <= ilimit) {
             /* Complementary insertion */
             /* done after iLimit test, as candidates could be > iend-8 */
-            {   U32 const indexToInsert = current+2;
+            {   U32 const indexToInsert = curr+2;
                 hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert;
                 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
                 hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert;
@@ -401,15 +401,15 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
         const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base;
         const BYTE* matchLong = matchLongBase + matchLongIndex;
 
-        const U32 current = (U32)(ip-base);
-        const U32 repIndex = current + 1 - offset_1;   /* offset_1 expected <= current +1 */
+        const U32 curr = (U32)(ip-base);
+        const U32 repIndex = curr + 1 - offset_1;   /* offset_1 expected <= curr +1 */
         const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
         const BYTE* const repMatch = repBase + repIndex;
         size_t mLength;
-        hashSmall[hSmall] = hashLong[hLong] = current;   /* update hash table */
+        hashSmall[hSmall] = hashLong[hLong] = curr;   /* update hash table */
 
         if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */
-            & (repIndex > dictStartIndex))
+            & (offset_1 < curr+1 - dictStartIndex)) /* note: we are searching at curr+1 */
           && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
             const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
             mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
@@ -421,7 +421,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
                 const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart;
                 U32 offset;
                 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8;
-                offset = current - matchLongIndex;
+                offset = curr - matchLongIndex;
                 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; }   /* catch up */
                 offset_2 = offset_1;
                 offset_1 = offset;
@@ -433,19 +433,19 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
                 const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base;
                 const BYTE* match3 = match3Base + matchIndex3;
                 U32 offset;
-                hashLong[h3] = current + 1;
+                hashLong[h3] = curr + 1;
                 if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
                     const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend;
                     const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart;
                     mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8;
                     ip++;
-                    offset = current+1 - matchIndex3;
+                    offset = curr+1 - matchIndex3;
                     while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
                 } else {
                     const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
                     const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
                     mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
-                    offset = current - matchIndex;
+                    offset = curr - matchIndex;
                     while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */
                 }
                 offset_2 = offset_1;
@@ -464,7 +464,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
         if (ip <= ilimit) {
             /* Complementary insertion */
             /* done after iLimit test, as candidates could be > iend-8 */
-            {   U32 const indexToInsert = current+2;
+            {   U32 const indexToInsert = curr+2;
                 hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert;
                 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
                 hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert;
@@ -477,7 +477,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
                 U32 const repIndex2 = current2 - offset_2;
                 const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
                 if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3)   /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */
-                    & (repIndex2 > dictStartIndex))
+                    & (offset_2 < current2 - dictStartIndex))
                   && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
                     const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
                     size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
index 14d944d..e16b7b0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
index 85a3a7a..4edc04d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -29,16 +29,16 @@ void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
      * Insert the other positions if their hash entry is empty.
      */
     for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) {
-        U32 const current = (U32)(ip - base);
+        U32 const curr = (U32)(ip - base);
         size_t const hash0 = ZSTD_hashPtr(ip, hBits, mls);
-        hashTable[hash0] = current;
+        hashTable[hash0] = curr;
         if (dtlm == ZSTD_dtlm_fast) continue;
         /* Only load extra positions for ZSTD_dtlm_full */
         {   U32 p;
             for (p = 1; p < fastHashFillStep; ++p) {
                 size_t const hash = ZSTD_hashPtr(ip + p, hBits, mls);
                 if (hashTable[hash] == 0) {  /* not yet filled */
-                    hashTable[hash] = current + p;
+                    hashTable[hash] = curr + p;
     }   }   }   }
 }
 
@@ -72,9 +72,9 @@ ZSTD_compressBlock_fast_generic(
     DEBUGLOG(5, "ZSTD_compressBlock_fast_generic");
     ip0 += (ip0 == prefixStart);
     ip1 = ip0 + 1;
-    {   U32 const current = (U32)(ip0 - base);
-        U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog);
-        U32 const maxRep = current - windowLow;
+    {   U32 const curr = (U32)(ip0 - base);
+        U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, cParams->windowLog);
+        U32 const maxRep = curr - windowLow;
         if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
         if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
     }
@@ -242,7 +242,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
     assert(endIndex - prefixStartIndex <= maxDistance);
     (void)maxDistance; (void)endIndex;   /* these variables are not used when assert() is disabled */
 
-    /* ensure there will be no no underflow
+    /* ensure there will be no underflow
      * when translating a dict index into a local index */
     assert(prefixStartIndex >= (U32)(dictEnd - dictBase));
 
@@ -258,14 +258,14 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
     while (ip < ilimit) {   /* < instead of <=, because repcode check at (ip+1) */
         size_t mLength;
         size_t const h = ZSTD_hashPtr(ip, hlog, mls);
-        U32 const current = (U32)(ip-base);
+        U32 const curr = (U32)(ip-base);
         U32 const matchIndex = hashTable[h];
         const BYTE* match = base + matchIndex;
-        const U32 repIndex = current + 1 - offset_1;
+        const U32 repIndex = curr + 1 - offset_1;
         const BYTE* repMatch = (repIndex < prefixStartIndex) ?
                                dictBase + (repIndex - dictIndexDelta) :
                                base + repIndex;
-        hashTable[h] = current;   /* update hash table */
+        hashTable[h] = curr;   /* update hash table */
 
         if ( ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */
           && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
@@ -284,7 +284,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
                 continue;
             } else {
                 /* found a dict match */
-                U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta);
+                U32 const offset = (U32)(curr-dictMatchIndex-dictIndexDelta);
                 mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4;
                 while (((ip>anchor) & (dictMatch>dictStart))
                      && (ip[-1] == dictMatch[-1])) {
@@ -316,8 +316,8 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
 
         if (ip <= ilimit) {
             /* Fill Table */
-            assert(base+current+2 > istart);  /* check base overflow */
-            hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2;  /* here because current+2 could be > iend-8 */
+            assert(base+curr+2 > istart);  /* check base overflow */
+            hashTable[ZSTD_hashPtr(base+curr+2, hlog, mls)] = curr+2;  /* here because curr+2 could be > iend-8 */
             hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
 
             /* check immediate repcode */
@@ -410,15 +410,15 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
         const U32    matchIndex = hashTable[h];
         const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
         const BYTE*  match = matchBase + matchIndex;
-        const U32    current = (U32)(ip-base);
-        const U32    repIndex = current + 1 - offset_1;
+        const U32    curr = (U32)(ip-base);
+        const U32    repIndex = curr + 1 - offset_1;
         const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
         const BYTE* const repMatch = repBase + repIndex;
-        hashTable[h] = current;   /* update hash table */
-        DEBUGLOG(7, "offset_1 = %u , current = %u", offset_1, current);
-        assert(offset_1 <= current +1);   /* check repIndex */
+        hashTable[h] = curr;   /* update hash table */
+        DEBUGLOG(7, "offset_1 = %u , curr = %u", offset_1, curr);
 
-        if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex))
+        if ( ( ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */
+             & (offset_1 < curr+1 - dictStartIndex) ) /* note: we are searching at curr+1 */
            && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
             const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
             size_t const rLength = ZSTD_count_2segments(ip+1 +4, repMatch +4, iend, repMatchEnd, prefixStart) + 4;
@@ -435,7 +435,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
             }
             {   const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
                 const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
-                U32 const offset = current - matchIndex;
+                U32 const offset = curr - matchIndex;
                 size_t mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
                 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */
                 offset_2 = offset_1; offset_1 = offset;  /* update offset history */
@@ -446,14 +446,14 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
 
         if (ip <= ilimit) {
             /* Fill Table */
-            hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2;
+            hashTable[ZSTD_hashPtr(base+curr+2, hlog, mls)] = curr+2;
             hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
             /* check immediate repcode */
             while (ip <= ilimit) {
                 U32 const current2 = (U32)(ip-base);
                 U32 const repIndex2 = current2 - offset_2;
                 const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
-                if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex))  /* intentional overflow */
+                if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (offset_2 < curr - dictStartIndex))  /* intentional overflow */
                    && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
                     const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
                     size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
index cf6aaa8..0d4a0c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
index 4cf5c88..6ce897d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -58,11 +58,11 @@ ZSTD_updateDUBT(ZSTD_matchState_t* ms,
 
 /** ZSTD_insertDUBT1() :
  *  sort one already inserted but unsorted position
- *  assumption : current >= btlow == (current - btmask)
+ *  assumption : curr >= btlow == (curr - btmask)
  *  doesn't fail */
 static void
 ZSTD_insertDUBT1(ZSTD_matchState_t* ms,
-                 U32 current, const BYTE* inputEnd,
+                 U32 curr, const BYTE* inputEnd,
                  U32 nbCompares, U32 btLow,
                  const ZSTD_dictMode_e dictMode)
 {
@@ -74,41 +74,41 @@ ZSTD_insertDUBT1(ZSTD_matchState_t* ms,
     const BYTE* const base = ms->window.base;
     const BYTE* const dictBase = ms->window.dictBase;
     const U32 dictLimit = ms->window.dictLimit;
-    const BYTE* const ip = (current>=dictLimit) ? base + current : dictBase + current;
-    const BYTE* const iend = (current>=dictLimit) ? inputEnd : dictBase + dictLimit;
+    const BYTE* const ip = (curr>=dictLimit) ? base + curr : dictBase + curr;
+    const BYTE* const iend = (curr>=dictLimit) ? inputEnd : dictBase + dictLimit;
     const BYTE* const dictEnd = dictBase + dictLimit;
     const BYTE* const prefixStart = base + dictLimit;
     const BYTE* match;
-    U32* smallerPtr = bt + 2*(current&btMask);
+    U32* smallerPtr = bt + 2*(curr&btMask);
     U32* largerPtr  = smallerPtr + 1;
     U32 matchIndex = *smallerPtr;   /* this candidate is unsorted : next sorted candidate is reached through *smallerPtr, while *largerPtr contains previous unsorted candidate (which is already saved and can be overwritten) */
     U32 dummy32;   /* to be nullified at the end */
     U32 const windowValid = ms->window.lowLimit;
     U32 const maxDistance = 1U << cParams->windowLog;
-    U32 const windowLow = (current - windowValid > maxDistance) ? current - maxDistance : windowValid;
+    U32 const windowLow = (curr - windowValid > maxDistance) ? curr - maxDistance : windowValid;
 
 
     DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)",
-                current, dictLimit, windowLow);
-    assert(current >= btLow);
+                curr, dictLimit, windowLow);
+    assert(curr >= btLow);
     assert(ip < iend);   /* condition for ZSTD_count */
 
     while (nbCompares-- && (matchIndex > windowLow)) {
         U32* const nextPtr = bt + 2*(matchIndex & btMask);
         size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
-        assert(matchIndex < current);
+        assert(matchIndex < curr);
         /* note : all candidates are now supposed sorted,
          * but it's still possible to have nextPtr[1] == ZSTD_DUBT_UNSORTED_MARK
          * when a real index has the same value as ZSTD_DUBT_UNSORTED_MARK */
 
         if ( (dictMode != ZSTD_extDict)
           || (matchIndex+matchLength >= dictLimit)  /* both in current segment*/
-          || (current < dictLimit) /* both in extDict */) {
+          || (curr < dictLimit) /* both in extDict */) {
             const BYTE* const mBase = ( (dictMode != ZSTD_extDict)
                                      || (matchIndex+matchLength >= dictLimit)) ?
                                         base : dictBase;
             assert( (matchIndex+matchLength >= dictLimit)   /* might be wrong if extDict is incorrectly set to 0 */
-                 || (current < dictLimit) );
+                 || (curr < dictLimit) );
             match = mBase + matchIndex;
             matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
         } else {
@@ -119,7 +119,7 @@ ZSTD_insertDUBT1(ZSTD_matchState_t* ms,
         }
 
         DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u : found %u common bytes ",
-                    current, matchIndex, (U32)matchLength);
+                    curr, matchIndex, (U32)matchLength);
 
         if (ip+matchLength == iend) {   /* equal : no way to know if inf or sup */
             break;   /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
@@ -168,7 +168,7 @@ ZSTD_DUBT_findBetterDictMatch (
 
     const BYTE* const base = ms->window.base;
     const BYTE* const prefixStart = base + ms->window.dictLimit;
-    U32         const current = (U32)(ip-base);
+    U32         const curr = (U32)(ip-base);
     const BYTE* const dictBase = dms->window.base;
     const BYTE* const dictEnd = dms->window.nextSrc;
     U32         const dictHighLimit = (U32)(dms->window.nextSrc - dms->window.base);
@@ -195,10 +195,10 @@ ZSTD_DUBT_findBetterDictMatch (
 
         if (matchLength > bestLength) {
             U32 matchIndex = dictMatchIndex + dictIndexDelta;
-            if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) {
+            if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(curr-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) {
                 DEBUGLOG(9, "ZSTD_DUBT_findBetterDictMatch(%u) : found better match length %u -> %u and offsetCode %u -> %u (dictMatchIndex %u, matchIndex %u)",
-                    current, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, ZSTD_REP_MOVE + current - matchIndex, dictMatchIndex, matchIndex);
-                bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
+                    curr, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, ZSTD_REP_MOVE + curr - matchIndex, dictMatchIndex, matchIndex);
+                bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + curr - matchIndex;
             }
             if (ip+matchLength == iend) {   /* reached end of input : ip[matchLength] is not valid, no way to know if it's larger or smaller than match */
                 break;   /* drop, to guarantee consistency (miss a little bit of compression) */
@@ -218,9 +218,9 @@ ZSTD_DUBT_findBetterDictMatch (
     }
 
     if (bestLength >= MINMATCH) {
-        U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
+        U32 const mIndex = curr - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
         DEBUGLOG(8, "ZSTD_DUBT_findBetterDictMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
-                    current, (U32)bestLength, (U32)*offsetPtr, mIndex);
+                    curr, (U32)bestLength, (U32)*offsetPtr, mIndex);
     }
     return bestLength;
 
@@ -241,13 +241,13 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
     U32          matchIndex  = hashTable[h];
 
     const BYTE* const base = ms->window.base;
-    U32    const current = (U32)(ip-base);
-    U32    const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog);
+    U32    const curr = (U32)(ip-base);
+    U32    const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog);
 
     U32*   const bt = ms->chainTable;
     U32    const btLog  = cParams->chainLog - 1;
     U32    const btMask = (1 << btLog) - 1;
-    U32    const btLow = (btMask >= current) ? 0 : current - btMask;
+    U32    const btLow = (btMask >= curr) ? 0 : curr - btMask;
     U32    const unsortLimit = MAX(btLow, windowLow);
 
     U32*         nextCandidate = bt + 2*(matchIndex&btMask);
@@ -256,8 +256,9 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
     U32          nbCandidates = nbCompares;
     U32          previousCandidate = 0;
 
-    DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", current);
+    DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", curr);
     assert(ip <= iend-8);   /* required for h calculation */
+    assert(dictMode != ZSTD_dedicatedDictSearch);
 
     /* reach end of unsorted candidates list */
     while ( (matchIndex > unsortLimit)
@@ -299,14 +300,14 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
         const U32 dictLimit = ms->window.dictLimit;
         const BYTE* const dictEnd = dictBase + dictLimit;
         const BYTE* const prefixStart = base + dictLimit;
-        U32* smallerPtr = bt + 2*(current&btMask);
-        U32* largerPtr  = bt + 2*(current&btMask) + 1;
-        U32 matchEndIdx = current + 8 + 1;
+        U32* smallerPtr = bt + 2*(curr&btMask);
+        U32* largerPtr  = bt + 2*(curr&btMask) + 1;
+        U32 matchEndIdx = curr + 8 + 1;
         U32 dummy32;   /* to be nullified at the end */
         size_t bestLength = 0;
 
         matchIndex  = hashTable[h];
-        hashTable[h] = current;   /* Update Hash Table */
+        hashTable[h] = curr;   /* Update Hash Table */
 
         while (nbCompares-- && (matchIndex > windowLow)) {
             U32* const nextPtr = bt + 2*(matchIndex & btMask);
@@ -326,8 +327,8 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
             if (matchLength > bestLength) {
                 if (matchLength > matchEndIdx - matchIndex)
                     matchEndIdx = matchIndex + (U32)matchLength;
-                if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
-                    bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
+                if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(curr-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
+                    bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + curr - matchIndex;
                 if (ip+matchLength == iend) {   /* equal : no way to know if inf or sup */
                     if (dictMode == ZSTD_dictMatchState) {
                         nbCompares = 0; /* in addition to avoiding checking any
@@ -363,12 +364,12 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
                     mls, dictMode);
         }
 
-        assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */
+        assert(matchEndIdx > curr+8); /* ensure nextToUpdate is increased */
         ms->nextToUpdate = matchEndIdx - 8;   /* skip repetitive patterns */
         if (bestLength >= MINMATCH) {
-            U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
+            U32 const mIndex = curr - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex;
             DEBUGLOG(8, "ZSTD_DUBT_findBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)",
-                        current, (U32)bestLength, (U32)*offsetPtr, mIndex);
+                        curr, (U32)bestLength, (U32)*offsetPtr, mIndex);
         }
         return bestLength;
     }
@@ -437,6 +438,220 @@ static size_t ZSTD_BtFindBestMatch_extDict_selectMLS (
     }
 }
 
+/***********************************
+* Dedicated dict search
+***********************************/
+
+void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip)
+{
+    const BYTE* const base = ms->window.base;
+    U32 const target = (U32)(ip - base);
+    U32* const hashTable = ms->hashTable;
+    U32* const chainTable = ms->chainTable;
+    U32 const chainSize = 1 << ms->cParams.chainLog;
+    U32 idx = ms->nextToUpdate;
+    U32 const minChain = chainSize < target ? target - chainSize : idx;
+    U32 const bucketSize = 1 << ZSTD_LAZY_DDSS_BUCKET_LOG;
+    U32 const cacheSize = bucketSize - 1;
+    U32 const chainAttempts = (1 << ms->cParams.searchLog) - cacheSize;
+    U32 const chainLimit = chainAttempts > 255 ? 255 : chainAttempts;
+
+    /* We know the hashtable is oversized by a factor of `bucketSize`.
+     * We are going to temporarily pretend `bucketSize == 1`, keeping only a
+     * single entry. We will use the rest of the space to construct a temporary
+     * chaintable.
+     */
+    U32 const hashLog = ms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG;
+    U32* const tmpHashTable = hashTable;
+    U32* const tmpChainTable = hashTable + ((size_t)1 << hashLog);
+    U32 const tmpChainSize = ((1 << ZSTD_LAZY_DDSS_BUCKET_LOG) - 1) << hashLog;
+    U32 const tmpMinChain = tmpChainSize < target ? target - tmpChainSize : idx;
+    U32 hashIdx;
+
+    assert(ms->cParams.chainLog <= 24);
+    assert(ms->cParams.hashLog > ms->cParams.chainLog);
+    assert(idx != 0);
+    assert(tmpMinChain <= minChain);
+
+    /* fill conventional hash table and conventional chain table */
+    for ( ; idx < target; idx++) {
+        U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, ms->cParams.minMatch);
+        if (idx >= tmpMinChain) {
+            tmpChainTable[idx - tmpMinChain] = hashTable[h];
+        }
+        tmpHashTable[h] = idx;
+    }
+
+    /* sort chains into ddss chain table */
+    {
+        U32 chainPos = 0;
+        for (hashIdx = 0; hashIdx < (1U << hashLog); hashIdx++) {
+            U32 count;
+            U32 countBeyondMinChain = 0;
+            U32 i = tmpHashTable[hashIdx];
+            for (count = 0; i >= tmpMinChain && count < cacheSize; count++) {
+                /* skip through the chain to the first position that won't be
+                 * in the hash cache bucket */
+                if (i < minChain) {
+                    countBeyondMinChain++;
+                }
+                i = tmpChainTable[i - tmpMinChain];
+            }
+            if (count == cacheSize) {
+                for (count = 0; count < chainLimit;) {
+                    if (i < minChain) {
+                        if (!i || ++countBeyondMinChain > cacheSize) {
+                            /* only allow pulling `cacheSize` number of entries
+                             * into the cache or chainTable beyond `minChain`,
+                             * to replace the entries pulled out of the
+                             * chainTable into the cache. This lets us reach
+                             * back further without increasing the total number
+                             * of entries in the chainTable, guaranteeing the
+                             * DDSS chain table will fit into the space
+                             * allocated for the regular one. */
+                            break;
+                        }
+                    }
+                    chainTable[chainPos++] = i;
+                    count++;
+                    if (i < tmpMinChain) {
+                        break;
+                    }
+                    i = tmpChainTable[i - tmpMinChain];
+                }
+            } else {
+                count = 0;
+            }
+            if (count) {
+                tmpHashTable[hashIdx] = ((chainPos - count) << 8) + count;
+            } else {
+                tmpHashTable[hashIdx] = 0;
+            }
+        }
+        assert(chainPos <= chainSize); /* I believe this is guaranteed... */
+    }
+
+    /* move chain pointers into the last entry of each hash bucket */
+    for (hashIdx = (1 << hashLog); hashIdx; ) {
+        U32 const bucketIdx = --hashIdx << ZSTD_LAZY_DDSS_BUCKET_LOG;
+        U32 const chainPackedPointer = tmpHashTable[hashIdx];
+        U32 i;
+        for (i = 0; i < cacheSize; i++) {
+            hashTable[bucketIdx + i] = 0;
+        }
+        hashTable[bucketIdx + bucketSize - 1] = chainPackedPointer;
+    }
+
+    /* fill the buckets of the hash table */
+    for (idx = ms->nextToUpdate; idx < target; idx++) {
+        U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, ms->cParams.minMatch)
+                   << ZSTD_LAZY_DDSS_BUCKET_LOG;
+        U32 i;
+        /* Shift hash cache down 1. */
+        for (i = cacheSize - 1; i; i--)
+            hashTable[h + i] = hashTable[h + i - 1];
+        hashTable[h] = idx;
+    }
+
+    ms->nextToUpdate = target;
+}
+
+/* Returns the longest match length found in the dedicated dict search structure.
+ * If none are longer than the argument ml, then ml will be returned.
+ */
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_dedicatedDictSearch_lazy_search(size_t* offsetPtr, size_t ml, U32 nbAttempts,
+                                            const ZSTD_matchState_t* const dms,
+                                            const BYTE* const ip, const BYTE* const iLimit,
+                                            const BYTE* const prefixStart, const U32 curr,
+                                            const U32 dictLimit, const size_t ddsIdx) {
+    const U32 ddsLowestIndex  = dms->window.dictLimit;
+    const BYTE* const ddsBase = dms->window.base;
+    const BYTE* const ddsEnd  = dms->window.nextSrc;
+    const U32 ddsSize         = (U32)(ddsEnd - ddsBase);
+    const U32 ddsIndexDelta   = dictLimit - ddsSize;
+    const U32 bucketSize      = (1 << ZSTD_LAZY_DDSS_BUCKET_LOG);
+    const U32 bucketLimit     = nbAttempts < bucketSize - 1 ? nbAttempts : bucketSize - 1;
+    U32 ddsAttempt;
+    U32 matchIndex;
+
+    for (ddsAttempt = 0; ddsAttempt < bucketSize - 1; ddsAttempt++) {
+        PREFETCH_L1(ddsBase + dms->hashTable[ddsIdx + ddsAttempt]);
+    }
+
+    {
+        U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1];
+        U32 const chainIndex = chainPackedPointer >> 8;
+
+        PREFETCH_L1(&dms->chainTable[chainIndex]);
+    }
+
+    for (ddsAttempt = 0; ddsAttempt < bucketLimit; ddsAttempt++) {
+        size_t currentMl=0;
+        const BYTE* match;
+        matchIndex = dms->hashTable[ddsIdx + ddsAttempt];
+        match = ddsBase + matchIndex;
+
+        if (!matchIndex) {
+            return ml;
+        }
+
+        /* guaranteed by table construction */
+        (void)ddsLowestIndex;
+        assert(matchIndex >= ddsLowestIndex);
+        assert(match+4 <= ddsEnd);
+        if (MEM_read32(match) == MEM_read32(ip)) {
+            /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+            currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4;
+        }
+
+        /* save best solution */
+        if (currentMl > ml) {
+            ml = currentMl;
+            *offsetPtr = curr - (matchIndex + ddsIndexDelta) + ZSTD_REP_MOVE;
+            if (ip+currentMl == iLimit) {
+                /* best possible, avoids read overflow on next attempt */
+                return ml;
+            }
+        }
+    }
+
+    {
+        U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1];
+        U32 chainIndex = chainPackedPointer >> 8;
+        U32 const chainLength = chainPackedPointer & 0xFF;
+        U32 const chainAttempts = nbAttempts - ddsAttempt;
+        U32 const chainLimit = chainAttempts > chainLength ? chainLength : chainAttempts;
+        U32 chainAttempt;
+
+        for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++) {
+            PREFETCH_L1(ddsBase + dms->chainTable[chainIndex + chainAttempt]);
+        }
+
+        for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++, chainIndex++) {
+            size_t currentMl=0;
+            const BYTE* match;
+            matchIndex = dms->chainTable[chainIndex];
+            match = ddsBase + matchIndex;
+
+            /* guaranteed by table construction */
+            assert(matchIndex >= ddsLowestIndex);
+            assert(match+4 <= ddsEnd);
+            if (MEM_read32(match) == MEM_read32(ip)) {
+                /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+                currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4;
+            }
+
+            /* save best solution */
+            if (currentMl > ml) {
+                ml = currentMl;
+                *offsetPtr = curr - (matchIndex + ddsIndexDelta) + ZSTD_REP_MOVE;
+                if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
+            }
+        }
+    }
+    return ml;
+}
 
 
 /* *********************************
@@ -446,7 +661,7 @@ static size_t ZSTD_BtFindBestMatch_extDict_selectMLS (
 
 /* Update chains up to ip (excluded)
    Assumption : always within prefix (i.e. not within extDict) */
-static U32 ZSTD_insertAndFindFirstIndex_internal(
+FORCE_INLINE_TEMPLATE U32 ZSTD_insertAndFindFirstIndex_internal(
                         ZSTD_matchState_t* ms,
                         const ZSTD_compressionParameters* const cParams,
                         const BYTE* ip, U32 const mls)
@@ -475,7 +690,6 @@ U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) {
     return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch);
 }
 
-
 /* inlining is important to hardwire a hot branch (template emulation) */
 FORCE_INLINE_TEMPLATE
 size_t ZSTD_HcFindBestMatch_generic (
@@ -493,20 +707,33 @@ size_t ZSTD_HcFindBestMatch_generic (
     const U32 dictLimit = ms->window.dictLimit;
     const BYTE* const prefixStart = base + dictLimit;
     const BYTE* const dictEnd = dictBase + dictLimit;
-    const U32 current = (U32)(ip-base);
+    const U32 curr = (U32)(ip-base);
     const U32 maxDistance = 1U << cParams->windowLog;
     const U32 lowestValid = ms->window.lowLimit;
-    const U32 withinMaxDistance = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid;
+    const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid;
     const U32 isDictionary = (ms->loadedDictEnd != 0);
     const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance;
-    const U32 minChain = current > chainSize ? current - chainSize : 0;
+    const U32 minChain = curr > chainSize ? curr - chainSize : 0;
     U32 nbAttempts = 1U << cParams->searchLog;
     size_t ml=4-1;
 
+    const ZSTD_matchState_t* const dms = ms->dictMatchState;
+    const U32 ddsHashLog = dictMode == ZSTD_dedicatedDictSearch
+                         ? dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG : 0;
+    const size_t ddsIdx = dictMode == ZSTD_dedicatedDictSearch
+                        ? ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG : 0;
+
+    U32 matchIndex;
+
+    if (dictMode == ZSTD_dedicatedDictSearch) {
+        const U32* entry = &dms->hashTable[ddsIdx];
+        PREFETCH_L1(entry);
+    }
+
     /* HC4 match finder */
-    U32 matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls);
+    matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls);
 
-    for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
+    for ( ; (matchIndex>=lowLimit) & (nbAttempts>0) ; nbAttempts--) {
         size_t currentMl=0;
         if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) {
             const BYTE* const match = base + matchIndex;
@@ -523,7 +750,7 @@ size_t ZSTD_HcFindBestMatch_generic (
         /* save best solution */
         if (currentMl > ml) {
             ml = currentMl;
-            *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
+            *offsetPtr = curr - matchIndex + ZSTD_REP_MOVE;
             if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
         }
 
@@ -531,8 +758,10 @@ size_t ZSTD_HcFindBestMatch_generic (
         matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
     }
 
-    if (dictMode == ZSTD_dictMatchState) {
-        const ZSTD_matchState_t* const dms = ms->dictMatchState;
+    if (dictMode == ZSTD_dedicatedDictSearch) {
+        ml = ZSTD_dedicatedDictSearch_lazy_search(offsetPtr, ml, nbAttempts, dms,
+                                                  ip, iLimit, prefixStart, curr, dictLimit, ddsIdx);
+    } else if (dictMode == ZSTD_dictMatchState) {
         const U32* const dmsChainTable = dms->chainTable;
         const U32 dmsChainSize         = (1 << dms->cParams.chainLog);
         const U32 dmsChainMask         = dmsChainSize - 1;
@@ -545,7 +774,7 @@ size_t ZSTD_HcFindBestMatch_generic (
 
         matchIndex = dms->hashTable[ZSTD_hashPtr(ip, dms->cParams.hashLog, mls)];
 
-        for ( ; (matchIndex>dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) {
+        for ( ; (matchIndex>=dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) {
             size_t currentMl=0;
             const BYTE* const match = dmsBase + matchIndex;
             assert(match+4 <= dmsEnd);
@@ -555,11 +784,12 @@ size_t ZSTD_HcFindBestMatch_generic (
             /* save best solution */
             if (currentMl > ml) {
                 ml = currentMl;
-                *offsetPtr = current - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE;
+                *offsetPtr = curr - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE;
                 if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
             }
 
             if (matchIndex <= dmsMinChain) break;
+
             matchIndex = dmsChainTable[matchIndex & dmsChainMask];
         }
     }
@@ -600,6 +830,22 @@ static size_t ZSTD_HcFindBestMatch_dictMatchState_selectMLS (
 }
 
 
+static size_t ZSTD_HcFindBestMatch_dedicatedDictSearch_selectMLS (
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* const iLimit,
+                        size_t* offsetPtr)
+{
+    switch(ms->cParams.minMatch)
+    {
+    default : /* includes case 3 */
+    case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_dedicatedDictSearch);
+    case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_dedicatedDictSearch);
+    case 7 :
+    case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_dedicatedDictSearch);
+    }
+}
+
+
 FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
                         ZSTD_matchState_t* ms,
                         const BYTE* ip, const BYTE* const iLimit,
@@ -615,11 +861,658 @@ FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
     }
 }
 
+/* *********************************
+* (SIMD) Row-based matchfinder
+***********************************/
+/* Constants for row-based hash */
+#define ZSTD_ROW_HASH_TAG_OFFSET 1                               /* byte offset of hashes in the match state's tagTable from the beginning of a row */
+#define ZSTD_ROW_HASH_TAG_BITS 8                                 /* nb bits to use for the tag */
+#define ZSTD_ROW_HASH_TAG_MASK ((1u << ZSTD_ROW_HASH_TAG_BITS) - 1)
+
+#define ZSTD_ROW_HASH_CACHE_MASK (ZSTD_ROW_HASH_CACHE_SIZE - 1)
+
+typedef U32 ZSTD_VecMask;   /* Clarifies when we are interacting with a U32 representing a mask of matches */
+
+#if !defined(ZSTD_NO_INTRINSICS) && defined(__SSE2__) /* SIMD SSE version */
+
+#include <emmintrin.h>
+typedef __m128i ZSTD_Vec128;
+
+/* Returns a 128-bit container with 128-bits from src */
+static ZSTD_Vec128 ZSTD_Vec128_read(const void* const src) {
+  return _mm_loadu_si128((ZSTD_Vec128 const*)src);
+}
+
+/* Returns a ZSTD_Vec128 with the byte "val" packed 16 times */
+static ZSTD_Vec128 ZSTD_Vec128_set8(BYTE val) {
+  return _mm_set1_epi8((char)val);
+}
+
+/* Do byte-by-byte comparison result of x and y. Then collapse 128-bit resultant mask
+ * into a 32-bit mask that is the MSB of each byte.
+ * */
+static ZSTD_VecMask ZSTD_Vec128_cmpMask8(ZSTD_Vec128 x, ZSTD_Vec128 y) {
+  return (ZSTD_VecMask)_mm_movemask_epi8(_mm_cmpeq_epi8(x, y));
+}
+
+typedef struct {
+  __m128i fst;
+  __m128i snd;
+} ZSTD_Vec256;
+
+static ZSTD_Vec256 ZSTD_Vec256_read(const void* const ptr) {
+  ZSTD_Vec256 v;
+  v.fst = ZSTD_Vec128_read(ptr);
+  v.snd = ZSTD_Vec128_read((ZSTD_Vec128 const*)ptr + 1);
+  return v;
+}
+
+static ZSTD_Vec256 ZSTD_Vec256_set8(BYTE val) {
+  ZSTD_Vec256 v;
+  v.fst = ZSTD_Vec128_set8(val);
+  v.snd = ZSTD_Vec128_set8(val);
+  return v;
+}
+
+static ZSTD_VecMask ZSTD_Vec256_cmpMask8(ZSTD_Vec256 x, ZSTD_Vec256 y) {
+  ZSTD_VecMask fstMask;
+  ZSTD_VecMask sndMask;
+  fstMask = ZSTD_Vec128_cmpMask8(x.fst, y.fst);
+  sndMask = ZSTD_Vec128_cmpMask8(x.snd, y.snd);
+  return fstMask | (sndMask << 16);
+}
+
+#elif !defined(ZSTD_NO_INTRINSICS) && defined(__ARM_NEON) /* SIMD ARM NEON Version */
+
+#include <arm_neon.h>
+typedef uint8x16_t ZSTD_Vec128;
+
+static ZSTD_Vec128 ZSTD_Vec128_read(const void* const src) {
+  return vld1q_u8((const BYTE* const)src);
+}
+
+static ZSTD_Vec128 ZSTD_Vec128_set8(BYTE val) {
+  return vdupq_n_u8(val);
+}
+
+/* Mimics '_mm_movemask_epi8()' from SSE */
+static U32 ZSTD_vmovmaskq_u8(ZSTD_Vec128 val) {
+    /* Shift out everything but the MSB bits in each byte */
+    uint16x8_t highBits = vreinterpretq_u16_u8(vshrq_n_u8(val, 7));
+    /* Merge the even lanes together with vsra (right shift and add) */
+    uint32x4_t paired16 = vreinterpretq_u32_u16(vsraq_n_u16(highBits, highBits, 7));
+    uint64x2_t paired32 = vreinterpretq_u64_u32(vsraq_n_u32(paired16, paired16, 14));
+    uint8x16_t paired64 = vreinterpretq_u8_u64(vsraq_n_u64(paired32, paired32, 28));
+    /* Extract the low 8 bits from each lane, merge */
+    return vgetq_lane_u8(paired64, 0) | ((U32)vgetq_lane_u8(paired64, 8) << 8);
+}
+
+static ZSTD_VecMask ZSTD_Vec128_cmpMask8(ZSTD_Vec128 x, ZSTD_Vec128 y) {
+  return (ZSTD_VecMask)ZSTD_vmovmaskq_u8(vceqq_u8(x, y));
+}
+
+typedef struct {
+    uint8x16_t fst;
+    uint8x16_t snd;
+} ZSTD_Vec256;
+
+static ZSTD_Vec256 ZSTD_Vec256_read(const void* const ptr) {
+  ZSTD_Vec256 v;
+  v.fst = ZSTD_Vec128_read(ptr);
+  v.snd = ZSTD_Vec128_read((ZSTD_Vec128 const*)ptr + 1);
+  return v;
+}
+
+static ZSTD_Vec256 ZSTD_Vec256_set8(BYTE val) {
+  ZSTD_Vec256 v;
+  v.fst = ZSTD_Vec128_set8(val);
+  v.snd = ZSTD_Vec128_set8(val);
+  return v;
+}
+
+static ZSTD_VecMask ZSTD_Vec256_cmpMask8(ZSTD_Vec256 x, ZSTD_Vec256 y) {
+  ZSTD_VecMask fstMask;
+  ZSTD_VecMask sndMask;
+  fstMask = ZSTD_Vec128_cmpMask8(x.fst, y.fst);
+  sndMask = ZSTD_Vec128_cmpMask8(x.snd, y.snd);
+  return fstMask | (sndMask << 16);
+}
+
+#else /* Scalar fallback version */
+
+#define VEC128_NB_SIZE_T (16 / sizeof(size_t))
+typedef struct {
+    size_t vec[VEC128_NB_SIZE_T];
+} ZSTD_Vec128;
+
+static ZSTD_Vec128 ZSTD_Vec128_read(const void* const src) {
+    ZSTD_Vec128 ret;
+    ZSTD_memcpy(ret.vec, src, VEC128_NB_SIZE_T*sizeof(size_t));
+    return ret;
+}
+
+static ZSTD_Vec128 ZSTD_Vec128_set8(BYTE val) {
+    ZSTD_Vec128 ret = { {0} };
+    int startBit = sizeof(size_t) * 8 - 8;
+    for (;startBit >= 0; startBit -= 8) {
+        unsigned j = 0;
+        for (;j < VEC128_NB_SIZE_T; ++j) {
+            ret.vec[j] |= ((size_t)val << startBit);
+        }
+    }
+    return ret;
+}
+
+/* Compare x to y, byte by byte, generating a "matches" bitfield */
+static ZSTD_VecMask ZSTD_Vec128_cmpMask8(ZSTD_Vec128 x, ZSTD_Vec128 y) {
+    ZSTD_VecMask res = 0;
+    unsigned i = 0;
+    unsigned l = 0;
+    for (; i < VEC128_NB_SIZE_T; ++i) {
+        const size_t cmp1 = x.vec[i];
+        const size_t cmp2 = y.vec[i];
+        unsigned j = 0;
+        for (; j < sizeof(size_t); ++j, ++l) {
+            if (((cmp1 >> j*8) & 0xFF) == ((cmp2 >> j*8) & 0xFF)) {
+                res |= ((U32)1 << (j+i*sizeof(size_t)));
+            }
+        }
+    }
+    return res;
+}
+
+#define VEC256_NB_SIZE_T 2*VEC128_NB_SIZE_T
+typedef struct {
+    size_t vec[VEC256_NB_SIZE_T];
+} ZSTD_Vec256;
+
+static ZSTD_Vec256 ZSTD_Vec256_read(const void* const src) {
+    ZSTD_Vec256 ret;
+    ZSTD_memcpy(ret.vec, src, VEC256_NB_SIZE_T*sizeof(size_t));
+    return ret;
+}
+
+static ZSTD_Vec256 ZSTD_Vec256_set8(BYTE val) {
+    ZSTD_Vec256 ret = { {0} };
+    int startBit = sizeof(size_t) * 8 - 8;
+    for (;startBit >= 0; startBit -= 8) {
+        unsigned j = 0;
+        for (;j < VEC256_NB_SIZE_T; ++j) {
+            ret.vec[j] |= ((size_t)val << startBit);
+        }
+    }
+    return ret;
+}
+
+/* Compare x to y, byte by byte, generating a "matches" bitfield */
+static ZSTD_VecMask ZSTD_Vec256_cmpMask8(ZSTD_Vec256 x, ZSTD_Vec256 y) {
+    ZSTD_VecMask res = 0;
+    unsigned i = 0;
+    unsigned l = 0;
+    for (; i < VEC256_NB_SIZE_T; ++i) {
+        const size_t cmp1 = x.vec[i];
+        const size_t cmp2 = y.vec[i];
+        unsigned j = 0;
+        for (; j < sizeof(size_t); ++j, ++l) {
+            if (((cmp1 >> j*8) & 0xFF) == ((cmp2 >> j*8) & 0xFF)) {
+                res |= ((U32)1 << (j+i*sizeof(size_t)));
+            }
+        }
+    }
+    return res;
+}
+
+#endif /* !defined(ZSTD_NO_INTRINSICS) && defined(__SSE2__) */
+
+/* ZSTD_VecMask_next():
+ * Starting from the LSB, returns the idx of the next non-zero bit.
+ * Basically counting the nb of trailing zeroes.
+ */
+static U32 ZSTD_VecMask_next(ZSTD_VecMask val) {
+#   if defined(_MSC_VER)   /* Visual */
+    unsigned long r=0;
+    return _BitScanForward(&r, val) ? (U32)r : 0;
+#   elif defined(__GNUC__) && (__GNUC__ >= 3)
+    return (U32)__builtin_ctz(val);
+#   else
+    /* Software ctz version: http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup */
+    static const U32 multiplyDeBruijnBitPosition[32] =
+    {
+        0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+               31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+    };
+       return multiplyDeBruijnBitPosition[((U32)((val & -(int)val) * 0x077CB531U)) >> 27];
+
+#   endif
+}
+
+/* ZSTD_VecMask_rotateRight():
+ * Rotates a bitfield to the right by "rotation" bits.
+ * If the rotation is greater than totalBits, the returned mask is 0.
+ */
+FORCE_INLINE_TEMPLATE ZSTD_VecMask
+ZSTD_VecMask_rotateRight(ZSTD_VecMask mask, U32 const rotation, U32 const totalBits) {
+  if (rotation == 0)
+    return mask;
+  switch (totalBits) {
+    default:
+      assert(0);
+    case 16:
+      return (mask >> rotation) | (U16)(mask << (16 - rotation));
+    case 32:
+      return (mask >> rotation) | (U32)(mask << (32 - rotation));
+  }
+}
+
+/* ZSTD_row_nextIndex():
+ * Returns the next index to insert at within a tagTable row, and updates the "head"
+ * value to reflect the update. Essentially cycles backwards from [0, {entries per row})
+ */
+FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextIndex(BYTE* const tagRow, U32 const rowMask) {
+  U32 const next = (*tagRow - 1) & rowMask;
+  *tagRow = (BYTE)next;
+  return next;
+}
+
+/* ZSTD_isAligned():
+ * Checks that a pointer is aligned to "align" bytes which must be a power of 2.
+ */
+MEM_STATIC int ZSTD_isAligned(void const* ptr, size_t align) {
+    assert((align & (align - 1)) == 0);
+    return (((size_t)ptr) & (align - 1)) == 0;
+}
+
+/* ZSTD_row_prefetch():
+ * Performs prefetching for the hashTable and tagTable at a given row.
+ */
+FORCE_INLINE_TEMPLATE void ZSTD_row_prefetch(U32 const* hashTable, U16 const* tagTable, U32 const relRow, U32 const rowLog) {
+    PREFETCH_L1(hashTable + relRow);
+    if (rowLog == 5) {
+        PREFETCH_L1(hashTable + relRow + 16);
+    }
+    PREFETCH_L1(tagTable + relRow);
+    assert(rowLog == 4 || rowLog == 5);
+    assert(ZSTD_isAligned(hashTable + relRow, 64));                 /* prefetched hash row always 64-byte aligned */
+    assert(ZSTD_isAligned(tagTable + relRow, (size_t)1 << rowLog)); /* prefetched tagRow sits on a multiple of 32 or 64 bytes */
+}
+
+/* ZSTD_row_fillHashCache():
+ * Fill up the hash cache starting at idx, prefetching up to ZSTD_ROW_HASH_CACHE_SIZE entries,
+ * but not beyond iLimit.
+ */
+static void ZSTD_row_fillHashCache(ZSTD_matchState_t* ms, const BYTE* base,
+                                   U32 const rowLog, U32 const mls,
+                                   U32 idx, const BYTE* const iLimit)
+{
+    U32 const* const hashTable = ms->hashTable;
+    U16 const* const tagTable = ms->tagTable;
+    U32 const hashLog = ms->rowHashLog;
+    U32 const maxElemsToPrefetch = (base + idx) > iLimit ? 0 : (U32)(iLimit - (base + idx) + 1);
+    U32 const lim = idx + MIN(ZSTD_ROW_HASH_CACHE_SIZE, maxElemsToPrefetch);
+
+    for (; idx < lim; ++idx) {
+        U32 const hash = (U32)ZSTD_hashPtr(base + idx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls);
+        U32 const row = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
+        ZSTD_row_prefetch(hashTable, tagTable, row, rowLog);
+        ms->hashCache[idx & ZSTD_ROW_HASH_CACHE_MASK] = hash;
+    }
+
+    DEBUGLOG(6, "ZSTD_row_fillHashCache(): [%u %u %u %u %u %u %u %u]", ms->hashCache[0], ms->hashCache[1],
+                                                     ms->hashCache[2], ms->hashCache[3], ms->hashCache[4],
+                                                     ms->hashCache[5], ms->hashCache[6], ms->hashCache[7]);
+}
+
+/* ZSTD_row_nextCachedHash():
+ * Returns the hash of base + idx, and replaces the hash in the hash cache with the byte at
+ * base + idx + ZSTD_ROW_HASH_CACHE_SIZE. Also prefetches the appropriate rows from hashTable and tagTable.
+ */
+FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextCachedHash(U32* cache, U32 const* hashTable,
+                                                  U16 const* tagTable, BYTE const* base,
+                                                  U32 idx, U32 const hashLog,
+                                                  U32 const rowLog, U32 const mls)
+{
+    U32 const newHash = (U32)ZSTD_hashPtr(base+idx+ZSTD_ROW_HASH_CACHE_SIZE, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls);
+    U32 const row = (newHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
+    ZSTD_row_prefetch(hashTable, tagTable, row, rowLog);
+    {   U32 const hash = cache[idx & ZSTD_ROW_HASH_CACHE_MASK];
+        cache[idx & ZSTD_ROW_HASH_CACHE_MASK] = newHash;
+        return hash;
+    }
+}
+
+/* ZSTD_row_update_internal():
+ * Inserts the byte at ip into the appropriate position in the hash table.
+ * Determines the relative row, and the position within the {16, 32} entry row to insert at.
+ */
+FORCE_INLINE_TEMPLATE void ZSTD_row_update_internal(ZSTD_matchState_t* ms, const BYTE* ip,
+                                                    U32 const mls, U32 const rowLog,
+                                                    U32 const rowMask, U32 const useCache)
+{
+    U32* const hashTable = ms->hashTable;
+    U16* const tagTable = ms->tagTable;
+    U32 const hashLog = ms->rowHashLog;
+    const BYTE* const base = ms->window.base;
+    const U32 target = (U32)(ip - base);
+    U32 idx = ms->nextToUpdate;
+
+    DEBUGLOG(6, "ZSTD_row_update_internal(): nextToUpdate=%u, current=%u", idx, target);
+    for (; idx < target; ++idx) {
+        U32 const hash = useCache ? ZSTD_row_nextCachedHash(ms->hashCache, hashTable, tagTable, base, idx, hashLog, rowLog, mls)
+                                  : (U32)ZSTD_hashPtr(base + idx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls);
+        U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
+        U32* const row = hashTable + relRow;
+        BYTE* tagRow = (BYTE*)(tagTable + relRow);  /* Though tagTable is laid out as a table of U16, each tag is only 1 byte.
+                                                       Explicit cast allows us to get exact desired position within each row */
+        U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask);
+
+        assert(hash == ZSTD_hashPtr(base + idx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls));
+        ((BYTE*)tagRow)[pos + ZSTD_ROW_HASH_TAG_OFFSET] = hash & ZSTD_ROW_HASH_TAG_MASK;
+        row[pos] = idx;
+    }
+    ms->nextToUpdate = target;
+}
+
+/* ZSTD_row_update():
+ * External wrapper for ZSTD_row_update_internal(). Used for filling the hashtable during dictionary
+ * processing.
+ */
+void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip) {
+    const U32 rowLog = ms->cParams.searchLog < 5 ? 4 : 5;
+    const U32 rowMask = (1u << rowLog) - 1;
+    const U32 mls = MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */);
+
+    DEBUGLOG(5, "ZSTD_row_update(), rowLog=%u", rowLog);
+    ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 0 /* dont use cache */);
+}
+
+/* Returns a ZSTD_VecMask (U32) that has the nth bit set to 1 if the newly-computed "tag" matches
+ * the hash at the nth position in a row of the tagTable.
+ */
+FORCE_INLINE_TEMPLATE
+ZSTD_VecMask ZSTD_row_getMatchMask(const BYTE* const tagRow, const BYTE tag, const U32 head, const U32 rowEntries) {
+    ZSTD_VecMask matches = 0;
+    if (rowEntries == 16) {
+        ZSTD_Vec128 hashes        = ZSTD_Vec128_read(tagRow + ZSTD_ROW_HASH_TAG_OFFSET);
+        ZSTD_Vec128 expandedTags  = ZSTD_Vec128_set8(tag);
+        matches                   = ZSTD_Vec128_cmpMask8(hashes, expandedTags);
+    } else if (rowEntries == 32) {
+        ZSTD_Vec256 hashes        = ZSTD_Vec256_read(tagRow + ZSTD_ROW_HASH_TAG_OFFSET);
+        ZSTD_Vec256 expandedTags  = ZSTD_Vec256_set8(tag);
+        matches                   = ZSTD_Vec256_cmpMask8(hashes, expandedTags);
+    } else {
+        assert(0);
+    }
+    /* Each row is a circular buffer beginning at the value of "head". So we must rotate the "matches" bitfield
+        to match up with the actual layout of the entries within the hashTable */
+    return ZSTD_VecMask_rotateRight(matches, head, rowEntries);
+}
+
+/* The high-level approach of the SIMD row based match finder is as follows:
+ * - Figure out where to insert the new entry:
+ *      - Generate a hash from a byte along with an additional 1-byte "short hash". The additional byte is our "tag"
+ *      - The hashTable is effectively split into groups or "rows" of 16 or 32 entries of U32, and the hash determines
+ *        which row to insert into.
+ *      - Determine the correct position within the row to insert the entry into. Each row of 16 or 32 can
+ *        be considered as a circular buffer with a "head" index that resides in the tagTable.
+ *      - Also insert the "tag" into the equivalent row and position in the tagTable.
+ *          - Note: The tagTable has 17 or 33 1-byte entries per row, due to 16 or 32 tags, and 1 "head" entry.
+ *                  The 17 or 33 entry rows are spaced out to occur every 32 or 64 bytes, respectively,
+ *                  for alignment/performance reasons, leaving some bytes unused.
+ * - Use SIMD to efficiently compare the tags in the tagTable to the 1-byte "short hash" and
+ *   generate a bitfield that we can cycle through to check the collisions in the hash table.
+ * - Pick the longest match.
+ */
+FORCE_INLINE_TEMPLATE
+size_t ZSTD_RowFindBestMatch_generic (
+                        ZSTD_matchState_t* ms,
+                        const BYTE* const ip, const BYTE* const iLimit,
+                        size_t* offsetPtr,
+                        const U32 mls, const ZSTD_dictMode_e dictMode,
+                        const U32 rowLog)
+{
+    U32* const hashTable = ms->hashTable;
+    U16* const tagTable = ms->tagTable;
+    U32* const hashCache = ms->hashCache;
+    const U32 hashLog = ms->rowHashLog;
+    const ZSTD_compressionParameters* const cParams = &ms->cParams;
+    const BYTE* const base = ms->window.base;
+    const BYTE* const dictBase = ms->window.dictBase;
+    const U32 dictLimit = ms->window.dictLimit;
+    const BYTE* const prefixStart = base + dictLimit;
+    const BYTE* const dictEnd = dictBase + dictLimit;
+    const U32 curr = (U32)(ip-base);
+    const U32 maxDistance = 1U << cParams->windowLog;
+    const U32 lowestValid = ms->window.lowLimit;
+    const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid;
+    const U32 isDictionary = (ms->loadedDictEnd != 0);
+    const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance;
+    const U32 rowEntries = (1U << rowLog);
+    const U32 rowMask = rowEntries - 1;
+    const U32 cappedSearchLog = MIN(cParams->searchLog, rowLog); /* nb of searches is capped at nb entries per row */
+    U32 nbAttempts = 1U << cappedSearchLog;
+    size_t ml=4-1;
+
+    /* DMS/DDS variables that may be referenced laster */
+    const ZSTD_matchState_t* const dms = ms->dictMatchState;
+    size_t ddsIdx;
+    U32 ddsExtraAttempts; /* cctx hash tables are limited in searches, but allow extra searches into DDS */
+    U32 dmsTag;
+    U32* dmsRow;
+    BYTE* dmsTagRow;
+
+    if (dictMode == ZSTD_dedicatedDictSearch) {
+        const U32 ddsHashLog = dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG;
+        {   /* Prefetch DDS hashtable entry */
+            ddsIdx = ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG;
+            PREFETCH_L1(&dms->hashTable[ddsIdx]);
+        }
+        ddsExtraAttempts = cParams->searchLog > rowLog ? 1U << (cParams->searchLog - rowLog) : 0;
+    }
+
+    if (dictMode == ZSTD_dictMatchState) {
+        /* Prefetch DMS rows */
+        U32* const dmsHashTable = dms->hashTable;
+        U16* const dmsTagTable = dms->tagTable;
+        U32 const dmsHash = (U32)ZSTD_hashPtr(ip, dms->rowHashLog + ZSTD_ROW_HASH_TAG_BITS, mls);
+        U32 const dmsRelRow = (dmsHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
+        dmsTag = dmsHash & ZSTD_ROW_HASH_TAG_MASK;
+        dmsTagRow = (BYTE*)(dmsTagTable + dmsRelRow);
+        dmsRow = dmsHashTable + dmsRelRow;
+        ZSTD_row_prefetch(dmsHashTable, dmsTagTable, dmsRelRow, rowLog);
+    }
+
+    /* Update the hashTable and tagTable up to (but not including) ip */
+    ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 1 /* useCache */);
+    {   /* Get the hash for ip, compute the appropriate row */
+        U32 const hash = ZSTD_row_nextCachedHash(hashCache, hashTable, tagTable, base, curr, hashLog, rowLog, mls);
+        U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog;
+        U32 const tag = hash & ZSTD_ROW_HASH_TAG_MASK;
+        U32* const row = hashTable + relRow;
+        BYTE* tagRow = (BYTE*)(tagTable + relRow);
+        U32 const head = *tagRow & rowMask;
+        U32 matchBuffer[32 /* maximum nb entries per row */];
+        size_t numMatches = 0;
+        size_t currMatch = 0;
+        ZSTD_VecMask matches = ZSTD_row_getMatchMask(tagRow, (BYTE)tag, head, rowEntries);
+
+        /* Cycle through the matches and prefetch */
+        for (; (matches > 0) && (nbAttempts > 0); --nbAttempts, matches &= (matches - 1)) {
+            U32 const matchPos = (head + ZSTD_VecMask_next(matches)) & rowMask;
+            U32 const matchIndex = row[matchPos];
+            assert(numMatches < rowEntries);
+            if (matchIndex < lowLimit)
+                break;
+            if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) {
+                PREFETCH_L1(base + matchIndex);
+            } else {
+                PREFETCH_L1(dictBase + matchIndex);
+            }
+            matchBuffer[numMatches++] = matchIndex;
+        }
+
+        /* Speed opt: insert current byte into hashtable too. This allows us to avoid one iteration of the loop
+           in ZSTD_row_update_internal() at the next search. */
+        {
+            U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask);
+            tagRow[pos + ZSTD_ROW_HASH_TAG_OFFSET] = (BYTE)tag;
+            row[pos] = ms->nextToUpdate++;
+        }
+
+        /* Return the longest match */
+        for (; currMatch < numMatches; ++currMatch) {
+            U32 const matchIndex = matchBuffer[currMatch];
+            size_t currentMl=0;
+            assert(matchIndex < curr);
+            assert(matchIndex >= lowLimit);
+
+            if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) {
+                const BYTE* const match = base + matchIndex;
+                assert(matchIndex >= dictLimit);   /* ensures this is true if dictMode != ZSTD_extDict */
+                if (match[ml] == ip[ml])   /* potentially better */
+                    currentMl = ZSTD_count(ip, match, iLimit);
+            } else {
+                const BYTE* const match = dictBase + matchIndex;
+                assert(match+4 <= dictEnd);
+                if (MEM_read32(match) == MEM_read32(ip))   /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+                    currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
+            }
+
+            /* Save best solution */
+            if (currentMl > ml) {
+                ml = currentMl;
+                *offsetPtr = curr - matchIndex + ZSTD_REP_MOVE;
+                if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
+            }
+        }
+    }
+
+    if (dictMode == ZSTD_dedicatedDictSearch) {
+        ml = ZSTD_dedicatedDictSearch_lazy_search(offsetPtr, ml, nbAttempts + ddsExtraAttempts, dms,
+                                                  ip, iLimit, prefixStart, curr, dictLimit, ddsIdx);
+    } else if (dictMode == ZSTD_dictMatchState) {
+        /* TODO: Measure and potentially add prefetching to DMS */
+        const U32 dmsLowestIndex       = dms->window.dictLimit;
+        const BYTE* const dmsBase      = dms->window.base;
+        const BYTE* const dmsEnd       = dms->window.nextSrc;
+        const U32 dmsSize              = (U32)(dmsEnd - dmsBase);
+        const U32 dmsIndexDelta        = dictLimit - dmsSize;
+
+        {   U32 const head = *dmsTagRow & rowMask;
+            U32 matchBuffer[32 /* maximum nb row entries */];
+            size_t numMatches = 0;
+            size_t currMatch = 0;
+            ZSTD_VecMask matches = ZSTD_row_getMatchMask(dmsTagRow, (BYTE)dmsTag, head, rowEntries);
+
+            for (; (matches > 0) && (nbAttempts > 0); --nbAttempts, matches &= (matches - 1)) {
+                U32 const matchPos = (head + ZSTD_VecMask_next(matches)) & rowMask;
+                U32 const matchIndex = dmsRow[matchPos];
+                if (matchIndex < dmsLowestIndex)
+                    break;
+                PREFETCH_L1(dmsBase + matchIndex);
+                matchBuffer[numMatches++] = matchIndex;
+            }
+
+            /* Return the longest match */
+            for (; currMatch < numMatches; ++currMatch) {
+                U32 const matchIndex = matchBuffer[currMatch];
+                size_t currentMl=0;
+                assert(matchIndex >= dmsLowestIndex);
+                assert(matchIndex < curr);
+
+                {   const BYTE* const match = dmsBase + matchIndex;
+                    assert(match+4 <= dmsEnd);
+                    if (MEM_read32(match) == MEM_read32(ip))
+                        currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dmsEnd, prefixStart) + 4;
+                }
+
+                if (currentMl > ml) {
+                    ml = currentMl;
+                    *offsetPtr = curr - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE;
+                    if (ip+currentMl == iLimit) break;
+                }
+            }
+        }
+    }
+    return ml;
+}
+
+/* Inlining is important to hardwire a hot branch (template emulation) */
+FORCE_INLINE_TEMPLATE size_t ZSTD_RowFindBestMatch_selectMLS (
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* const iLimit,
+                        const ZSTD_dictMode_e dictMode, size_t* offsetPtr, const U32 rowLog)
+{
+    switch(ms->cParams.minMatch)
+    {
+    default : /* includes case 3 */
+    case 4 : return ZSTD_RowFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, dictMode, rowLog);
+    case 5 : return ZSTD_RowFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, dictMode, rowLog);
+    case 7 :
+    case 6 : return ZSTD_RowFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, dictMode, rowLog);
+    }
+}
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_RowFindBestMatch_selectRowLog (
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* const iLimit,
+                        size_t* offsetPtr)
+{
+    const U32 cappedSearchLog = MIN(ms->cParams.searchLog, 5);
+    switch(cappedSearchLog)
+    {
+    default :
+    case 4 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_noDict, offsetPtr, 4);
+    case 5 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_noDict, offsetPtr, 5);
+    }
+}
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_RowFindBestMatch_dictMatchState_selectRowLog(
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* const iLimit,
+                        size_t* offsetPtr)
+{
+    const U32 cappedSearchLog = MIN(ms->cParams.searchLog, 5);
+    switch(cappedSearchLog)
+    {
+    default :
+    case 4 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_dictMatchState, offsetPtr, 4);
+    case 5 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_dictMatchState, offsetPtr, 5);
+    }
+}
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_RowFindBestMatch_dedicatedDictSearch_selectRowLog(
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* const iLimit,
+                        size_t* offsetPtr)
+{
+    const U32 cappedSearchLog = MIN(ms->cParams.searchLog, 5);
+    switch(cappedSearchLog)
+    {
+    default :
+    case 4 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_dedicatedDictSearch, offsetPtr, 4);
+    case 5 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_dedicatedDictSearch, offsetPtr, 5);
+    }
+}
+
+FORCE_INLINE_TEMPLATE size_t ZSTD_RowFindBestMatch_extDict_selectRowLog (
+                        ZSTD_matchState_t* ms,
+                        const BYTE* ip, const BYTE* const iLimit,
+                        size_t* offsetPtr)
+{
+    const U32 cappedSearchLog = MIN(ms->cParams.searchLog, 5);
+    switch(cappedSearchLog)
+    {
+    default :
+    case 4 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_extDict, offsetPtr, 4);
+    case 5 : return ZSTD_RowFindBestMatch_selectMLS(ms, ip, iLimit, ZSTD_extDict, offsetPtr, 5);
+    }
+}
+
 
 /* *******************************
 *  Common parser - lazy strategy
 *********************************/
-typedef enum { search_hashChain, search_binaryTree } searchMethod_e;
+typedef enum { search_hashChain=0, search_binaryTree=1, search_rowHash=2 } searchMethod_e;
 
 FORCE_INLINE_TEMPLATE size_t
 ZSTD_compressBlock_lazy_generic(
@@ -633,53 +1526,85 @@ ZSTD_compressBlock_lazy_generic(
     const BYTE* ip = istart;
     const BYTE* anchor = istart;
     const BYTE* const iend = istart + srcSize;
-    const BYTE* const ilimit = iend - 8;
+    const BYTE* const ilimit = searchMethod == search_rowHash ? iend - 8 - ZSTD_ROW_HASH_CACHE_SIZE : iend - 8;
     const BYTE* const base = ms->window.base;
     const U32 prefixLowestIndex = ms->window.dictLimit;
     const BYTE* const prefixLowest = base + prefixLowestIndex;
+    const U32 rowLog = ms->cParams.searchLog < 5 ? 4 : 5;
 
     typedef size_t (*searchMax_f)(
                         ZSTD_matchState_t* ms,
                         const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
-    searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ?
-        (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS
-                                         : ZSTD_HcFindBestMatch_dictMatchState_selectMLS) :
-        (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_selectMLS
-                                         : ZSTD_HcFindBestMatch_selectMLS);
+
+    /**
+     * This table is indexed first by the four ZSTD_dictMode_e values, and then
+     * by the two searchMethod_e values. NULLs are placed for configurations
+     * that should never occur (extDict modes go to the other implementation
+     * below and there is no DDSS for binary tree search yet).
+     */
+    const searchMax_f searchFuncs[4][3] = {
+        {
+            ZSTD_HcFindBestMatch_selectMLS,
+            ZSTD_BtFindBestMatch_selectMLS,
+            ZSTD_RowFindBestMatch_selectRowLog
+        },
+        {
+            NULL,
+            NULL,
+            NULL
+        },
+        {
+            ZSTD_HcFindBestMatch_dictMatchState_selectMLS,
+            ZSTD_BtFindBestMatch_dictMatchState_selectMLS,
+            ZSTD_RowFindBestMatch_dictMatchState_selectRowLog
+        },
+        {
+            ZSTD_HcFindBestMatch_dedicatedDictSearch_selectMLS,
+            NULL,
+            ZSTD_RowFindBestMatch_dedicatedDictSearch_selectRowLog
+        }
+    };
+
+    searchMax_f const searchMax = searchFuncs[dictMode][(int)searchMethod];
     U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0;
 
+    const int isDMS = dictMode == ZSTD_dictMatchState;
+    const int isDDS = dictMode == ZSTD_dedicatedDictSearch;
+    const int isDxS = isDMS || isDDS;
     const ZSTD_matchState_t* const dms = ms->dictMatchState;
-    const U32 dictLowestIndex      = dictMode == ZSTD_dictMatchState ?
-                                     dms->window.dictLimit : 0;
-    const BYTE* const dictBase     = dictMode == ZSTD_dictMatchState ?
-                                     dms->window.base : NULL;
-    const BYTE* const dictLowest   = dictMode == ZSTD_dictMatchState ?
-                                     dictBase + dictLowestIndex : NULL;
-    const BYTE* const dictEnd      = dictMode == ZSTD_dictMatchState ?
-                                     dms->window.nextSrc : NULL;
-    const U32 dictIndexDelta       = dictMode == ZSTD_dictMatchState ?
+    const U32 dictLowestIndex      = isDxS ? dms->window.dictLimit : 0;
+    const BYTE* const dictBase     = isDxS ? dms->window.base : NULL;
+    const BYTE* const dictLowest   = isDxS ? dictBase + dictLowestIndex : NULL;
+    const BYTE* const dictEnd      = isDxS ? dms->window.nextSrc : NULL;
+    const U32 dictIndexDelta       = isDxS ?
                                      prefixLowestIndex - (U32)(dictEnd - dictBase) :
                                      0;
     const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictLowest));
 
-    DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u)", (U32)dictMode);
+    assert(searchMax != NULL);
 
-    /* init */
+    DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u) (searchFunc=%u)", (U32)dictMode, (U32)searchMethod);
     ip += (dictAndPrefixLength == 0);
     if (dictMode == ZSTD_noDict) {
-        U32 const current = (U32)(ip - base);
-        U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, ms->cParams.windowLog);
-        U32 const maxRep = current - windowLow;
+        U32 const curr = (U32)(ip - base);
+        U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, ms->cParams.windowLog);
+        U32 const maxRep = curr - windowLow;
         if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
         if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
     }
-    if (dictMode == ZSTD_dictMatchState) {
+    if (isDxS) {
         /* dictMatchState repCode checks don't currently handle repCode == 0
          * disabling. */
         assert(offset_1 <= dictAndPrefixLength);
         assert(offset_2 <= dictAndPrefixLength);
     }
 
+    if (searchMethod == search_rowHash) {
+        ZSTD_row_fillHashCache(ms, base, rowLog,
+                            MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */),
+                            ms->nextToUpdate, ilimit);
+    }
+
     /* Match Loop */
 #if defined(__GNUC__) && defined(__x86_64__)
     /* I've measured random a 5% speed loss on levels 5 & 6 (greedy) when the
@@ -693,9 +1618,9 @@ ZSTD_compressBlock_lazy_generic(
         const BYTE* start=ip+1;
 
         /* check repCode */
-        if (dictMode == ZSTD_dictMatchState) {
+        if (isDxS) {
             const U32 repIndex = (U32)(ip - base) + 1 - offset_1;
-            const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
+            const BYTE* repMatch = ((dictMode == ZSTD_dictMatchState || dictMode == ZSTD_dedicatedDictSearch)
                                 && repIndex < prefixLowestIndex) ?
                                    dictBase + (repIndex - dictIndexDelta) :
                                    base + repIndex;
@@ -736,7 +1661,7 @@ ZSTD_compressBlock_lazy_generic(
                 if ((mlRep >= 4) && (gain2 > gain1))
                     matchLength = mlRep, offset = 0, start = ip;
             }
-            if (dictMode == ZSTD_dictMatchState) {
+            if (isDxS) {
                 const U32 repIndex = (U32)(ip - base) - offset_1;
                 const BYTE* repMatch = repIndex < prefixLowestIndex ?
                                dictBase + (repIndex - dictIndexDelta) :
@@ -771,7 +1696,7 @@ ZSTD_compressBlock_lazy_generic(
                     if ((mlRep >= 4) && (gain2 > gain1))
                         matchLength = mlRep, offset = 0, start = ip;
                 }
-                if (dictMode == ZSTD_dictMatchState) {
+                if (isDxS) {
                     const U32 repIndex = (U32)(ip - base) - offset_1;
                     const BYTE* repMatch = repIndex < prefixLowestIndex ?
                                    dictBase + (repIndex - dictIndexDelta) :
@@ -809,7 +1734,7 @@ ZSTD_compressBlock_lazy_generic(
                      && (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) )  /* only search for offset within prefix */
                     { start--; matchLength++; }
             }
-            if (dictMode == ZSTD_dictMatchState) {
+            if (isDxS) {
                 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
                 const BYTE* match = (matchIndex < prefixLowestIndex) ? dictBase + matchIndex - dictIndexDelta : base + matchIndex;
                 const BYTE* const mStart = (matchIndex < prefixLowestIndex) ? dictLowest : prefixLowest;
@@ -825,12 +1750,11 @@ _storeSequence:
         }
 
         /* check immediate repcode */
-        if (dictMode == ZSTD_dictMatchState) {
+        if (isDxS) {
             while (ip <= ilimit) {
                 U32 const current2 = (U32)(ip-base);
                 U32 const repIndex = current2 - offset_2;
-                const BYTE* repMatch = dictMode == ZSTD_dictMatchState
-                    && repIndex < prefixLowestIndex ?
+                const BYTE* repMatch = repIndex < prefixLowestIndex ?
                         dictBase - dictIndexDelta + repIndex :
                         base + repIndex;
                 if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex) >= 3 /* intentional overflow */)
@@ -925,6 +1849,92 @@ size_t ZSTD_compressBlock_greedy_dictMatchState(
 }
 
 
+size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dedicatedDictSearch);
+}
+
+size_t ZSTD_compressBlock_lazy_dedicatedDictSearch(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dedicatedDictSearch);
+}
+
+size_t ZSTD_compressBlock_greedy_dedicatedDictSearch(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dedicatedDictSearch);
+}
+
+/* Row-based matchfinder */
+size_t ZSTD_compressBlock_lazy2_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_lazy_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_greedy_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_noDict);
+}
+
+size_t ZSTD_compressBlock_lazy2_dictMatchState_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_lazy_dictMatchState_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dictMatchState);
+}
+
+size_t ZSTD_compressBlock_greedy_dictMatchState_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dictMatchState);
+}
+
+
+size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dedicatedDictSearch);
+}
+
+size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dedicatedDictSearch);
+}
+
+size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dedicatedDictSearch);
+}
+
 FORCE_INLINE_TEMPLATE
 size_t ZSTD_compressBlock_lazy_extDict_generic(
                         ZSTD_matchState_t* ms, seqStore_t* seqStore,
@@ -936,7 +1946,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
     const BYTE* ip = istart;
     const BYTE* anchor = istart;
     const BYTE* const iend = istart + srcSize;
-    const BYTE* const ilimit = iend - 8;
+    const BYTE* const ilimit = searchMethod == search_rowHash ? iend - 8 - ZSTD_ROW_HASH_CACHE_SIZE : iend - 8;
     const BYTE* const base = ms->window.base;
     const U32 dictLimit = ms->window.dictLimit;
     const BYTE* const prefixStart = base + dictLimit;
@@ -944,18 +1954,28 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
     const BYTE* const dictEnd  = dictBase + dictLimit;
     const BYTE* const dictStart  = dictBase + ms->window.lowLimit;
     const U32 windowLog = ms->cParams.windowLog;
+    const U32 rowLog = ms->cParams.searchLog < 5 ? 4 : 5;
 
     typedef size_t (*searchMax_f)(
                         ZSTD_matchState_t* ms,
                         const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
-    searchMax_f searchMax = searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS;
-
+    const searchMax_f searchFuncs[3] = {
+        ZSTD_HcFindBestMatch_extDict_selectMLS,
+        ZSTD_BtFindBestMatch_extDict_selectMLS,
+        ZSTD_RowFindBestMatch_extDict_selectRowLog
+    };
+    searchMax_f searchMax = searchFuncs[(int)searchMethod];
     U32 offset_1 = rep[0], offset_2 = rep[1];
 
-    DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic");
+    DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic (searchFunc=%u)", (U32)searchMethod);
 
     /* init */
     ip += (ip == prefixStart);
+    if (searchMethod == search_rowHash) {
+        ZSTD_row_fillHashCache(ms, base, rowLog,
+                               MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */),
+                               ms->nextToUpdate, ilimit);
+    }
 
     /* Match Loop */
 #if defined(__GNUC__) && defined(__x86_64__)
@@ -968,14 +1988,15 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
         size_t matchLength=0;
         size_t offset=0;
         const BYTE* start=ip+1;
-        U32 current = (U32)(ip-base);
+        U32 curr = (U32)(ip-base);
 
         /* check repCode */
-        {   const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current+1, windowLog);
-            const U32 repIndex = (U32)(current+1 - offset_1);
+        {   const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr+1, windowLog);
+            const U32 repIndex = (U32)(curr+1 - offset_1);
             const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
             const BYTE* const repMatch = repBase + repIndex;
-            if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow))   /* intentional overflow */
+            if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
+               & (offset_1 < curr+1 - windowLow) ) /* note: we are searching at curr+1 */
             if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
                 /* repcode detected we should take it */
                 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
@@ -999,14 +2020,15 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
         if (depth>=1)
         while (ip<ilimit) {
             ip ++;
-            current++;
+            curr++;
             /* check repCode */
             if (offset) {
-                const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current, windowLog);
-                const U32 repIndex = (U32)(current - offset_1);
+                const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr, windowLog);
+                const U32 repIndex = (U32)(curr - offset_1);
                 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
                 const BYTE* const repMatch = repBase + repIndex;
-                if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow))  /* intentional overflow */
+                if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments  */
+                   & (offset_1 < curr - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */
                 if (MEM_read32(ip) == MEM_read32(repMatch)) {
                     /* repcode detected */
                     const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
@@ -1030,14 +2052,15 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
             /* let's find an even better one */
             if ((depth==2) && (ip<ilimit)) {
                 ip ++;
-                current++;
+                curr++;
                 /* check repCode */
                 if (offset) {
-                    const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current, windowLog);
-                    const U32 repIndex = (U32)(current - offset_1);
+                    const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr, windowLog);
+                    const U32 repIndex = (U32)(curr - offset_1);
                     const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
                     const BYTE* const repMatch = repBase + repIndex;
-                    if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow))  /* intentional overflow */
+                    if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments  */
+                       & (offset_1 < curr - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */
                     if (MEM_read32(ip) == MEM_read32(repMatch)) {
                         /* repcode detected */
                         const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
@@ -1083,7 +2106,8 @@ _storeSequence:
             const U32 repIndex = repCurrent - offset_2;
             const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
             const BYTE* const repMatch = repBase + repIndex;
-            if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow))  /* intentional overflow */
+            if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments  */
+               & (offset_2 < repCurrent - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */
             if (MEM_read32(ip) == MEM_read32(repMatch)) {
                 /* repcode detected we should take it */
                 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
@@ -1136,3 +2160,26 @@ size_t ZSTD_compressBlock_btlazy2_extDict(
 {
     return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2);
 }
+
+size_t ZSTD_compressBlock_greedy_extDict_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+{
+    return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0);
+}
+
+size_t ZSTD_compressBlock_lazy_extDict_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+
+{
+    return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1);
+}
+
+size_t ZSTD_compressBlock_lazy2_extDict_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize)
+
+{
+    return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2);
+}
index 581936f..150f7b3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -17,7 +17,18 @@ extern "C" {
 
 #include "zstd_compress_internal.h"
 
+/**
+ * Dedicated Dictionary Search Structure bucket log. In the
+ * ZSTD_dedicatedDictSearch mode, the hashTable has
+ * 2 ** ZSTD_LAZY_DDSS_BUCKET_LOG entries in each bucket, rather than just
+ * one.
+ */
+#define ZSTD_LAZY_DDSS_BUCKET_LOG 2
+
 U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip);
+void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip);
+
+void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip);
 
 void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue);  /*! used in ZSTD_reduceIndex(). preemptively increase value of ZSTD_DUBT_UNSORTED_MARK */
 
@@ -33,6 +44,15 @@ size_t ZSTD_compressBlock_lazy(
 size_t ZSTD_compressBlock_greedy(
         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
         void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
 
 size_t ZSTD_compressBlock_btlazy2_dictMatchState(
         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
@@ -46,6 +66,34 @@ size_t ZSTD_compressBlock_lazy_dictMatchState(
 size_t ZSTD_compressBlock_greedy_dictMatchState(
         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
         void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_dictMatchState_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_dictMatchState_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_dictMatchState_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+
+size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_dedicatedDictSearch(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_dedicatedDictSearch(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
 
 size_t ZSTD_compressBlock_greedy_extDict(
         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
@@ -56,9 +104,19 @@ size_t ZSTD_compressBlock_lazy_extDict(
 size_t ZSTD_compressBlock_lazy2_extDict(
         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
         void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_greedy_extDict_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy_extDict_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
+size_t ZSTD_compressBlock_lazy2_extDict_row(
+        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+        void const* src, size_t srcSize);
 size_t ZSTD_compressBlock_btlazy2_extDict(
         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
         void const* src, size_t srcSize);
+        
 
 #if defined (__cplusplus)
 }
index 8c47948..fa4ebea 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
 #include "zstd_ldm.h"
 
 #include "../common/debug.h"
+#include "../common/xxhash.h"
 #include "zstd_fast.h"          /* ZSTD_fillHashTable() */
 #include "zstd_double_fast.h"   /* ZSTD_fillDoubleHashTable() */
+#include "zstd_ldm_geartab.h"
 
 #define LDM_BUCKET_SIZE_LOG 3
 #define LDM_MIN_MATCH_LENGTH 64
 #define LDM_HASH_RLOG 7
-#define LDM_HASH_CHAR_OFFSET 10
+
+typedef struct {
+    U64 rolling;
+    U64 stopMask;
+} ldmRollingHashState_t;
+
+/** ZSTD_ldm_gear_init():
+ *
+ * Initializes the rolling hash state such that it will honor the
+ * settings in params. */
+static void ZSTD_ldm_gear_init(ldmRollingHashState_t* state, ldmParams_t const* params)
+{
+    unsigned maxBitsInMask = MIN(params->minMatchLength, 64);
+    unsigned hashRateLog = params->hashRateLog;
+
+    state->rolling = ~(U32)0;
+
+    /* The choice of the splitting criterion is subject to two conditions:
+     *   1. it has to trigger on average every 2^(hashRateLog) bytes;
+     *   2. ideally, it has to depend on a window of minMatchLength bytes.
+     *
+     * In the gear hash algorithm, bit n depends on the last n bytes;
+     * so in order to obtain a good quality splitting criterion it is
+     * preferable to use bits with high weight.
+     *
+     * To match condition 1 we use a mask with hashRateLog bits set
+     * and, because of the previous remark, we make sure these bits
+     * have the highest possible weight while still respecting
+     * condition 2.
+     */
+    if (hashRateLog > 0 && hashRateLog <= maxBitsInMask) {
+        state->stopMask = (((U64)1 << hashRateLog) - 1) << (maxBitsInMask - hashRateLog);
+    } else {
+        /* In this degenerate case we simply honor the hash rate. */
+        state->stopMask = ((U64)1 << hashRateLog) - 1;
+    }
+}
+
+/** ZSTD_ldm_gear_reset()
+ * Feeds [data, data + minMatchLength) into the hash without registering any
+ * splits. This effectively resets the hash state. This is used when skipping
+ * over data, either at the beginning of a block, or skipping sections.
+ */
+static void ZSTD_ldm_gear_reset(ldmRollingHashState_t* state,
+                                BYTE const* data, size_t minMatchLength)
+{
+    U64 hash = state->rolling;
+    size_t n = 0;
+
+#define GEAR_ITER_ONCE() do {                                  \
+        hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \
+        n += 1;                                                \
+    } while (0)
+    while (n + 3 < minMatchLength) {
+        GEAR_ITER_ONCE();
+        GEAR_ITER_ONCE();
+        GEAR_ITER_ONCE();
+        GEAR_ITER_ONCE();
+    }
+    while (n < minMatchLength) {
+        GEAR_ITER_ONCE();
+    }
+#undef GEAR_ITER_ONCE
+}
+
+/** ZSTD_ldm_gear_feed():
+ *
+ * Registers in the splits array all the split points found in the first
+ * size bytes following the data pointer. This function terminates when
+ * either all the data has been processed or LDM_BATCH_SIZE splits are
+ * present in the splits array.
+ *
+ * Precondition: The splits array must not be full.
+ * Returns: The number of bytes processed. */
+static size_t ZSTD_ldm_gear_feed(ldmRollingHashState_t* state,
+                                 BYTE const* data, size_t size,
+                                 size_t* splits, unsigned* numSplits)
+{
+    size_t n;
+    U64 hash, mask;
+
+    hash = state->rolling;
+    mask = state->stopMask;
+    n = 0;
+
+#define GEAR_ITER_ONCE() do { \
+        hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \
+        n += 1; \
+        if (UNLIKELY((hash & mask) == 0)) { \
+            splits[*numSplits] = n; \
+            *numSplits += 1; \
+            if (*numSplits == LDM_BATCH_SIZE) \
+                goto done; \
+        } \
+    } while (0)
+
+    while (n + 3 < size) {
+        GEAR_ITER_ONCE();
+        GEAR_ITER_ONCE();
+        GEAR_ITER_ONCE();
+        GEAR_ITER_ONCE();
+    }
+    while (n < size) {
+        GEAR_ITER_ONCE();
+    }
+
+#undef GEAR_ITER_ONCE
+
+done:
+    state->rolling = hash;
+    return n;
+}
 
 void ZSTD_ldm_adjustParameters(ldmParams_t* params,
                                ZSTD_compressionParameters const* cParams)
@@ -27,13 +140,6 @@ void ZSTD_ldm_adjustParameters(ldmParams_t* params,
     DEBUGLOG(4, "ZSTD_ldm_adjustParameters");
     if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
     if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH;
-    if (cParams->strategy >= ZSTD_btopt) {
-      /* Get out of the way of the optimal parser */
-      U32 const minMatch = MAX(cParams->targetLength, params->minMatchLength);
-      assert(minMatch >= ZSTD_LDM_MINMATCH_MIN);
-      assert(minMatch <= ZSTD_LDM_MINMATCH_MAX);
-      params->minMatchLength = minMatch;
-    }
     if (params->hashLog == 0) {
         params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG);
         assert(params->hashLog <= ZSTD_HASHLOG_MAX);
@@ -61,41 +167,6 @@ size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize)
     return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0;
 }
 
-/** ZSTD_ldm_getSmallHash() :
- *  numBits should be <= 32
- *  If numBits==0, returns 0.
- *  @return : the most significant numBits of value. */
-static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits)
-{
-    assert(numBits <= 32);
-    return numBits == 0 ? 0 : (U32)(value >> (64 - numBits));
-}
-
-/** ZSTD_ldm_getChecksum() :
- *  numBitsToDiscard should be <= 32
- *  @return : the next most significant 32 bits after numBitsToDiscard */
-static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard)
-{
-    assert(numBitsToDiscard <= 32);
-    return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF;
-}
-
-/** ZSTD_ldm_getTag() ;
- *  Given the hash, returns the most significant numTagBits bits
- *  after (32 + hbits) bits.
- *
- *  If there are not enough bits remaining, return the last
- *  numTagBits bits. */
-static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits)
-{
-    assert(numTagBits < 32 && hbits <= 32);
-    if (32 - hbits < numTagBits) {
-        return hash & (((U32)1 << numTagBits) - 1);
-    } else {
-        return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1);
-    }
-}
-
 /** ZSTD_ldm_getBucket() :
  *  Returns a pointer to the start of the bucket associated with hash. */
 static ldmEntry_t* ZSTD_ldm_getBucket(
@@ -110,38 +181,12 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
                                  size_t const hash, const ldmEntry_t entry,
                                  ldmParams_t const ldmParams)
 {
-    BYTE* const bucketOffsets = ldmState->bucketOffsets;
-    *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry;
-    bucketOffsets[hash]++;
-    bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1;
-}
+    BYTE* const pOffset = ldmState->bucketOffsets + hash;
+    unsigned const offset = *pOffset;
+
+    *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + offset) = entry;
+    *pOffset = (BYTE)((offset + 1) & ((1u << ldmParams.bucketSizeLog) - 1));
 
-/** ZSTD_ldm_makeEntryAndInsertByTag() :
- *
- *  Gets the small hash, checksum, and tag from the rollingHash.
- *
- *  If the tag matches (1 << ldmParams.hashRateLog)-1, then
- *  creates an ldmEntry from the offset, and inserts it into the hash table.
- *
- *  hBits is the length of the small hash, which is the most significant hBits
- *  of rollingHash. The checksum is the next 32 most significant bits, followed
- *  by ldmParams.hashRateLog bits that make up the tag. */
-static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
-                                             U64 const rollingHash,
-                                             U32 const hBits,
-                                             U32 const offset,
-                                             ldmParams_t const ldmParams)
-{
-    U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashRateLog);
-    U32 const tagMask = ((U32)1 << ldmParams.hashRateLog) - 1;
-    if (tag == tagMask) {
-        U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits);
-        U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
-        ldmEntry_t entry;
-        entry.offset = offset;
-        entry.checksum = checksum;
-        ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams);
-    }
 }
 
 /** ZSTD_ldm_countBackwardsMatch() :
@@ -150,10 +195,10 @@ static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
  *  We count only bytes where pMatch >= pBase and pIn >= pAnchor. */
 static size_t ZSTD_ldm_countBackwardsMatch(
             const BYTE* pIn, const BYTE* pAnchor,
-            const BYTE* pMatch, const BYTE* pBase)
+            const BYTE* pMatch, const BYTE* pMatchBase)
 {
     size_t matchLength = 0;
-    while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) {
+    while (pIn > pAnchor && pMatch > pMatchBase && pIn[-1] == pMatch[-1]) {
         pIn--;
         pMatch--;
         matchLength++;
@@ -161,6 +206,27 @@ static size_t ZSTD_ldm_countBackwardsMatch(
     return matchLength;
 }
 
+/** ZSTD_ldm_countBackwardsMatch_2segments() :
+ *  Returns the number of bytes that match backwards from pMatch,
+ *  even with the backwards match spanning 2 different segments.
+ *
+ *  On reaching `pMatchBase`, start counting from mEnd */
+static size_t ZSTD_ldm_countBackwardsMatch_2segments(
+                    const BYTE* pIn, const BYTE* pAnchor,
+                    const BYTE* pMatch, const BYTE* pMatchBase,
+                    const BYTE* pExtDictStart, const BYTE* pExtDictEnd)
+{
+    size_t matchLength = ZSTD_ldm_countBackwardsMatch(pIn, pAnchor, pMatch, pMatchBase);
+    if (pMatch - matchLength != pMatchBase || pMatchBase == pExtDictStart) {
+        /* If backwards match is entirely in the extDict or prefix, immediately return */
+        return matchLength;
+    }
+    DEBUGLOG(7, "ZSTD_ldm_countBackwardsMatch_2segments: found 2-parts backwards match (length in prefix==%zu)", matchLength);
+    matchLength += ZSTD_ldm_countBackwardsMatch(pIn - matchLength, pAnchor, pExtDictEnd, pExtDictStart);
+    DEBUGLOG(7, "final backwards match length = %zu", matchLength);
+    return matchLength;
+}
+
 /** ZSTD_ldm_fillFastTables() :
  *
  *  Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies.
@@ -198,43 +264,42 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
     return 0;
 }
 
-/** ZSTD_ldm_fillLdmHashTable() :
- *
- *  Fills hashTable from (lastHashed + 1) to iend (non-inclusive).
- *  lastHash is the rolling hash that corresponds to lastHashed.
- *
- *  Returns the rolling hash corresponding to position iend-1. */
-static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
-                                     U64 lastHash, const BYTE* lastHashed,
-                                     const BYTE* iend, const BYTE* base,
-                                     U32 hBits, ldmParams_t const ldmParams)
-{
-    U64 rollingHash = lastHash;
-    const BYTE* cur = lastHashed + 1;
-
-    while (cur < iend) {
-        rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1],
-                                              cur[ldmParams.minMatchLength-1],
-                                              state->hashPower);
-        ZSTD_ldm_makeEntryAndInsertByTag(state,
-                                         rollingHash, hBits,
-                                         (U32)(cur - base), ldmParams);
-        ++cur;
-    }
-    return rollingHash;
-}
-
 void ZSTD_ldm_fillHashTable(
-            ldmState_t* state, const BYTE* ip,
+            ldmState_t* ldmState, const BYTE* ip,
             const BYTE* iend, ldmParams_t const* params)
 {
+    U32 const minMatchLength = params->minMatchLength;
+    U32 const hBits = params->hashLog - params->bucketSizeLog;
+    BYTE const* const base = ldmState->window.base;
+    BYTE const* const istart = ip;
+    ldmRollingHashState_t hashState;
+    size_t* const splits = ldmState->splitIndices;
+    unsigned numSplits;
+
     DEBUGLOG(5, "ZSTD_ldm_fillHashTable");
-    if ((size_t)(iend - ip) >= params->minMatchLength) {
-        U64 startingHash = ZSTD_rollingHash_compute(ip, params->minMatchLength);
-        ZSTD_ldm_fillLdmHashTable(
-            state, startingHash, ip, iend - params->minMatchLength, state->window.base,
-            params->hashLog - params->bucketSizeLog,
-            *params);
+
+    ZSTD_ldm_gear_init(&hashState, params);
+    while (ip < iend) {
+        size_t hashed;
+        unsigned n;
+
+        numSplits = 0;
+        hashed = ZSTD_ldm_gear_feed(&hashState, ip, iend - ip, splits, &numSplits);
+
+        for (n = 0; n < numSplits; n++) {
+            if (ip + splits[n] >= istart + minMatchLength) {
+                BYTE const* const split = ip + splits[n] - minMatchLength;
+                U64 const xxhash = XXH64(split, minMatchLength, 0);
+                U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1));
+                ldmEntry_t entry;
+
+                entry.offset = (U32)(split - base);
+                entry.checksum = (U32)(xxhash >> 32);
+                ZSTD_ldm_insertEntry(ldmState, hash, entry, *params);
+            }
+        }
+
+        ip += hashed;
     }
 }
 
@@ -246,10 +311,10 @@ void ZSTD_ldm_fillHashTable(
  *  (after a long match, only update tables a limited amount). */
 static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor)
 {
-    U32 const current = (U32)(anchor - ms->window.base);
-    if (current > ms->nextToUpdate + 1024) {
+    U32 const curr = (U32)(anchor - ms->window.base);
+    if (curr > ms->nextToUpdate + 1024) {
         ms->nextToUpdate =
-            current - MIN(512, current - ms->nextToUpdate - 1024);
+            curr - MIN(512, curr - ms->nextToUpdate - 1024);
     }
 }
 
@@ -260,11 +325,8 @@ static size_t ZSTD_ldm_generateSequences_internal(
     /* LDM parameters */
     int const extDict = ZSTD_window_hasExtDict(ldmState->window);
     U32 const minMatchLength = params->minMatchLength;
-    U64 const hashPower = ldmState->hashPower;
+    U32 const entsPerBucket = 1U << params->bucketSizeLog;
     U32 const hBits = params->hashLog - params->bucketSizeLog;
-    U32 const ldmBucketSize = 1U << params->bucketSizeLog;
-    U32 const hashRateLog = params->hashRateLog;
-    U32 const ldmTagMask = (1U << params->hashRateLog) - 1;
     /* Prefix and extDict parameters */
     U32 const dictLimit = ldmState->window.dictLimit;
     U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit;
@@ -276,45 +338,69 @@ static size_t ZSTD_ldm_generateSequences_internal(
     /* Input bounds */
     BYTE const* const istart = (BYTE const*)src;
     BYTE const* const iend = istart + srcSize;
-    BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE);
+    BYTE const* const ilimit = iend - HASH_READ_SIZE;
     /* Input positions */
     BYTE const* anchor = istart;
     BYTE const* ip = istart;
-    /* Rolling hash */
-    BYTE const* lastHashed = NULL;
-    U64 rollingHash = 0;
-
-    while (ip <= ilimit) {
-        size_t mLength;
-        U32 const current = (U32)(ip - base);
-        size_t forwardMatchLength = 0, backwardMatchLength = 0;
-        ldmEntry_t* bestEntry = NULL;
-        if (ip != istart) {
-            rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0],
-                                                  lastHashed[minMatchLength],
-                                                  hashPower);
-        } else {
-            rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength);
+    /* Rolling hash state */
+    ldmRollingHashState_t hashState;
+    /* Arrays for staged-processing */
+    size_t* const splits = ldmState->splitIndices;
+    ldmMatchCandidate_t* const candidates = ldmState->matchCandidates;
+    unsigned numSplits;
+
+    if (srcSize < minMatchLength)
+        return iend - anchor;
+
+    /* Initialize the rolling hash state with the first minMatchLength bytes */
+    ZSTD_ldm_gear_init(&hashState, params);
+    ZSTD_ldm_gear_reset(&hashState, ip, minMatchLength);
+    ip += minMatchLength;
+
+    while (ip < ilimit) {
+        size_t hashed;
+        unsigned n;
+
+        numSplits = 0;
+        hashed = ZSTD_ldm_gear_feed(&hashState, ip, ilimit - ip,
+                                    splits, &numSplits);
+
+        for (n = 0; n < numSplits; n++) {
+            BYTE const* const split = ip + splits[n] - minMatchLength;
+            U64 const xxhash = XXH64(split, minMatchLength, 0);
+            U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1));
+
+            candidates[n].split = split;
+            candidates[n].hash = hash;
+            candidates[n].checksum = (U32)(xxhash >> 32);
+            candidates[n].bucket = ZSTD_ldm_getBucket(ldmState, hash, *params);
+            PREFETCH_L1(candidates[n].bucket);
         }
-        lastHashed = ip;
 
-        /* Do not insert and do not look for a match */
-        if (ZSTD_ldm_getTag(rollingHash, hBits, hashRateLog) != ldmTagMask) {
-           ip++;
-           continue;
-        }
+        for (n = 0; n < numSplits; n++) {
+            size_t forwardMatchLength = 0, backwardMatchLength = 0,
+                   bestMatchLength = 0, mLength;
+            U32 offset;
+            BYTE const* const split = candidates[n].split;
+            U32 const checksum = candidates[n].checksum;
+            U32 const hash = candidates[n].hash;
+            ldmEntry_t* const bucket = candidates[n].bucket;
+            ldmEntry_t const* cur;
+            ldmEntry_t const* bestEntry = NULL;
+            ldmEntry_t newEntry;
+
+            newEntry.offset = (U32)(split - base);
+            newEntry.checksum = checksum;
+
+            /* If a split point would generate a sequence overlapping with
+             * the previous one, we merely register it in the hash table and
+             * move on */
+            if (split < anchor) {
+                ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
+                continue;
+            }
 
-        /* Get the best entry and compute the match lengths */
-        {
-            ldmEntry_t* const bucket =
-                ZSTD_ldm_getBucket(ldmState,
-                                   ZSTD_ldm_getSmallHash(rollingHash, hBits),
-                                   *params);
-            ldmEntry_t* cur;
-            size_t bestMatchLength = 0;
-            U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
-
-            for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
+            for (cur = bucket; cur < bucket + entsPerBucket; cur++) {
                 size_t curForwardMatchLength, curBackwardMatchLength,
                        curTotalMatchLength;
                 if (cur->checksum != checksum || cur->offset <= lowestIndex) {
@@ -328,30 +414,23 @@ static size_t ZSTD_ldm_generateSequences_internal(
                         cur->offset < dictLimit ? dictEnd : iend;
                     BYTE const* const lowMatchPtr =
                         cur->offset < dictLimit ? dictStart : lowPrefixPtr;
-
-                    curForwardMatchLength = ZSTD_count_2segments(
-                                                ip, pMatch, iend,
-                                                matchEnd, lowPrefixPtr);
+                    curForwardMatchLength =
+                        ZSTD_count_2segments(split, pMatch, iend, matchEnd, lowPrefixPtr);
                     if (curForwardMatchLength < minMatchLength) {
                         continue;
                     }
-                    curBackwardMatchLength =
-                        ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
-                                                     lowMatchPtr);
-                    curTotalMatchLength = curForwardMatchLength +
-                                          curBackwardMatchLength;
+                    curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch_2segments(
+                            split, anchor, pMatch, lowMatchPtr, dictStart, dictEnd);
                 } else { /* !extDict */
                     BYTE const* const pMatch = base + cur->offset;
-                    curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
+                    curForwardMatchLength = ZSTD_count(split, pMatch, iend);
                     if (curForwardMatchLength < minMatchLength) {
                         continue;
                     }
                     curBackwardMatchLength =
-                        ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
-                                                     lowPrefixPtr);
-                    curTotalMatchLength = curForwardMatchLength +
-                                          curBackwardMatchLength;
+                        ZSTD_ldm_countBackwardsMatch(split, anchor, pMatch, lowPrefixPtr);
                 }
+                curTotalMatchLength = curForwardMatchLength + curBackwardMatchLength;
 
                 if (curTotalMatchLength > bestMatchLength) {
                     bestMatchLength = curTotalMatchLength;
@@ -360,57 +439,54 @@ static size_t ZSTD_ldm_generateSequences_internal(
                     bestEntry = cur;
                 }
             }
-        }
-
-        /* No match found -- continue searching */
-        if (bestEntry == NULL) {
-            ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash,
-                                             hBits, current,
-                                             *params);
-            ip++;
-            continue;
-        }
 
-        /* Match found */
-        mLength = forwardMatchLength + backwardMatchLength;
-        ip -= backwardMatchLength;
+            /* No match found -- insert an entry into the hash table
+             * and process the next candidate match */
+            if (bestEntry == NULL) {
+                ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
+                continue;
+            }
 
-        {
-            /* Store the sequence:
-             * ip = current - backwardMatchLength
-             * The match is at (bestEntry->offset - backwardMatchLength)
-             */
-            U32 const matchIndex = bestEntry->offset;
-            U32 const offset = current - matchIndex;
-            rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
-
-            /* Out of sequence storage */
-            if (rawSeqStore->size == rawSeqStore->capacity)
-                return ERROR(dstSize_tooSmall);
-            seq->litLength = (U32)(ip - anchor);
-            seq->matchLength = (U32)mLength;
-            seq->offset = offset;
-            rawSeqStore->size++;
-        }
+            /* Match found */
+            offset = (U32)(split - base) - bestEntry->offset;
+            mLength = forwardMatchLength + backwardMatchLength;
+            {
+                rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
+
+                /* Out of sequence storage */
+                if (rawSeqStore->size == rawSeqStore->capacity)
+                    return ERROR(dstSize_tooSmall);
+                seq->litLength = (U32)(split - backwardMatchLength - anchor);
+                seq->matchLength = (U32)mLength;
+                seq->offset = offset;
+                rawSeqStore->size++;
+            }
 
-        /* Insert the current entry into the hash table */
-        ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
-                                         (U32)(lastHashed - base),
-                                         *params);
+            /* Insert the current entry into the hash table --- it must be
+             * done after the previous block to avoid clobbering bestEntry */
+            ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
 
-        assert(ip + backwardMatchLength == lastHashed);
+            anchor = split + forwardMatchLength;
 
-        /* Fill the hash table from lastHashed+1 to ip+mLength*/
-        /* Heuristic: don't need to fill the entire table at end of block */
-        if (ip + mLength <= ilimit) {
-            rollingHash = ZSTD_ldm_fillLdmHashTable(
-                              ldmState, rollingHash, lastHashed,
-                              ip + mLength, base, hBits, *params);
-            lastHashed = ip + mLength - 1;
+            /* If we find a match that ends after the data that we've hashed
+             * then we have a repeating, overlapping, pattern. E.g. all zeros.
+             * If one repetition of the pattern matches our `stopMask` then all
+             * repetitions will. We don't need to insert them all into out table,
+             * only the first one. So skip over overlapping matches.
+             * This is a major speed boost (20x) for compressing a single byte
+             * repeated, when that byte ends up in the table.
+             */
+            if (anchor > ip + hashed) {
+                ZSTD_ldm_gear_reset(&hashState, anchor - minMatchLength, minMatchLength);
+                /* Continue the outter loop at anchor (ip + hashed == anchor). */
+                ip = anchor - hashed;
+                break;
+            }
         }
-        ip += mLength;
-        anchor = ip;
+
+        ip += hashed;
     }
+
     return iend - anchor;
 }
 
@@ -459,7 +535,7 @@ size_t ZSTD_ldm_generateSequences(
 
         assert(chunkStart < iend);
         /* 1. Perform overflow correction if necessary. */
-        if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) {
+        if (ZSTD_window_needOverflowCorrection(ldmState->window, 0, maxDist, ldmState->loadedDictEnd, chunkStart, chunkEnd)) {
             U32 const ldmHSize = 1U << params->hashLog;
             U32 const correction = ZSTD_window_correctOverflow(
                 &ldmState->window, /* cycleLog */ 0, maxDist, chunkStart);
@@ -562,14 +638,32 @@ static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore,
     return sequence;
 }
 
+void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) {
+    U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes);
+    while (currPos && rawSeqStore->pos < rawSeqStore->size) {
+        rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos];
+        if (currPos >= currSeq.litLength + currSeq.matchLength) {
+            currPos -= currSeq.litLength + currSeq.matchLength;
+            rawSeqStore->pos++;
+        } else {
+            rawSeqStore->posInSequence = currPos;
+            break;
+        }
+    }
+    if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) {
+        rawSeqStore->posInSequence = 0;
+    }
+}
+
 size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
     ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+    ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
     void const* src, size_t srcSize)
 {
     const ZSTD_compressionParameters* const cParams = &ms->cParams;
     unsigned const minMatch = cParams->minMatch;
     ZSTD_blockCompressor const blockCompressor =
-        ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms));
+        ZSTD_selectBlockCompressor(cParams->strategy, useRowMatchFinder, ZSTD_matchState_dictMode(ms));
     /* Input bounds */
     BYTE const* const istart = (BYTE const*)src;
     BYTE const* const iend = istart + srcSize;
@@ -577,9 +671,18 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
     BYTE const* ip = istart;
 
     DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize);
+    /* If using opt parser, use LDMs only as candidates rather than always accepting them */
+    if (cParams->strategy >= ZSTD_btopt) {
+        size_t lastLLSize;
+        ms->ldmSeqStore = rawSeqStore;
+        lastLLSize = blockCompressor(ms, seqStore, rep, src, srcSize);
+        ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore, srcSize);
+        return lastLLSize;
+    }
+
     assert(rawSeqStore->pos <= rawSeqStore->size);
     assert(rawSeqStore->size <= rawSeqStore->capacity);
-    /* Loop through each sequence and apply the block compressor to the lits */
+    /* Loop through each sequence and apply the block compressor to the literals */
     while (rawSeqStore->pos < rawSeqStore->size && ip < iend) {
         /* maybeSplitSequence updates rawSeqStore->pos */
         rawSeq const sequence = maybeSplitSequence(rawSeqStore,
index 229ea05..393466f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -66,6 +66,7 @@ size_t ZSTD_ldm_generateSequences(
  */
 size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
             ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
+            ZSTD_useRowMatchFinderMode_e useRowMatchFinder,
             void const* src, size_t srcSize);
 
 /**
@@ -73,11 +74,17 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
  *
  * Skip past `srcSize` bytes worth of sequences in `rawSeqStore`.
  * Avoids emitting matches less than `minMatch` bytes.
- * Must be called for data with is not passed to ZSTD_ldm_blockCompress().
+ * Must be called for data that is not passed to ZSTD_ldm_blockCompress().
  */
 void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize,
     U32 const minMatch);
 
+/* ZSTD_ldm_skipRawSeqStoreBytes():
+ * Moves forward in rawSeqStore by nbBytes, updating fields 'pos' and 'posInSequence'.
+ * Not to be used in conjunction with ZSTD_ldm_skipSequences().
+ * Must be called for data with is not passed to ZSTD_ldm_blockCompress().
+ */
+void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes);
 
 /** ZSTD_ldm_getTableSize() :
  *  Estimate the space needed for long distance matching tables or 0 if LDM is
diff --git a/Utilities/cmzstd/lib/compress/zstd_ldm_geartab.h b/Utilities/cmzstd/lib/compress/zstd_ldm_geartab.h
new file mode 100644 (file)
index 0000000..e5c24d8
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef ZSTD_LDM_GEARTAB_H
+#define ZSTD_LDM_GEARTAB_H
+
+static U64 ZSTD_ldm_gearTab[256] = {
+    0xf5b8f72c5f77775c, 0x84935f266b7ac412, 0xb647ada9ca730ccc,
+    0xb065bb4b114fb1de, 0x34584e7e8c3a9fd0, 0x4e97e17c6ae26b05,
+    0x3a03d743bc99a604, 0xcecd042422c4044f, 0x76de76c58524259e,
+    0x9c8528f65badeaca, 0x86563706e2097529, 0x2902475fa375d889,
+    0xafb32a9739a5ebe6, 0xce2714da3883e639, 0x21eaf821722e69e,
+    0x37b628620b628,    0x49a8d455d88caf5,  0x8556d711e6958140,
+    0x4f7ae74fc605c1f,  0x829f0c3468bd3a20, 0x4ffdc885c625179e,
+    0x8473de048a3daf1b, 0x51008822b05646b2, 0x69d75d12b2d1cc5f,
+    0x8c9d4a19159154bc, 0xc3cc10f4abbd4003, 0xd06ddc1cecb97391,
+    0xbe48e6e7ed80302e, 0x3481db31cee03547, 0xacc3f67cdaa1d210,
+    0x65cb771d8c7f96cc, 0x8eb27177055723dd, 0xc789950d44cd94be,
+    0x934feadc3700b12b, 0x5e485f11edbdf182, 0x1e2e2a46fd64767a,
+    0x2969ca71d82efa7c, 0x9d46e9935ebbba2e, 0xe056b67e05e6822b,
+    0x94d73f55739d03a0, 0xcd7010bdb69b5a03, 0x455ef9fcd79b82f4,
+    0x869cb54a8749c161, 0x38d1a4fa6185d225, 0xb475166f94bbe9bb,
+    0xa4143548720959f1, 0x7aed4780ba6b26ba, 0xd0ce264439e02312,
+    0x84366d746078d508, 0xa8ce973c72ed17be, 0x21c323a29a430b01,
+    0x9962d617e3af80ee, 0xab0ce91d9c8cf75b, 0x530e8ee6d19a4dbc,
+    0x2ef68c0cf53f5d72, 0xc03a681640a85506, 0x496e4e9f9c310967,
+    0x78580472b59b14a0, 0x273824c23b388577, 0x66bf923ad45cb553,
+    0x47ae1a5a2492ba86, 0x35e304569e229659, 0x4765182a46870b6f,
+    0x6cbab625e9099412, 0xddac9a2e598522c1, 0x7172086e666624f2,
+    0xdf5003ca503b7837, 0x88c0c1db78563d09, 0x58d51865acfc289d,
+    0x177671aec65224f1, 0xfb79d8a241e967d7, 0x2be1e101cad9a49a,
+    0x6625682f6e29186b, 0x399553457ac06e50, 0x35dffb4c23abb74,
+    0x429db2591f54aade, 0xc52802a8037d1009, 0x6acb27381f0b25f3,
+    0xf45e2551ee4f823b, 0x8b0ea2d99580c2f7, 0x3bed519cbcb4e1e1,
+    0xff452823dbb010a,  0x9d42ed614f3dd267, 0x5b9313c06257c57b,
+    0xa114b8008b5e1442, 0xc1fe311c11c13d4b, 0x66e8763ea34c5568,
+    0x8b982af1c262f05d, 0xee8876faaa75fbb7, 0x8a62a4d0d172bb2a,
+    0xc13d94a3b7449a97, 0x6dbbba9dc15d037c, 0xc786101f1d92e0f1,
+    0xd78681a907a0b79b, 0xf61aaf2962c9abb9, 0x2cfd16fcd3cb7ad9,
+    0x868c5b6744624d21, 0x25e650899c74ddd7, 0xba042af4a7c37463,
+    0x4eb1a539465a3eca, 0xbe09dbf03b05d5ca, 0x774e5a362b5472ba,
+    0x47a1221229d183cd, 0x504b0ca18ef5a2df, 0xdffbdfbde2456eb9,
+    0x46cd2b2fbee34634, 0xf2aef8fe819d98c3, 0x357f5276d4599d61,
+    0x24a5483879c453e3, 0x88026889192b4b9,  0x28da96671782dbec,
+    0x4ef37c40588e9aaa, 0x8837b90651bc9fb3, 0xc164f741d3f0e5d6,
+    0xbc135a0a704b70ba, 0x69cd868f7622ada,  0xbc37ba89e0b9c0ab,
+    0x47c14a01323552f6, 0x4f00794bacee98bb, 0x7107de7d637a69d5,
+    0x88af793bb6f2255e, 0xf3c6466b8799b598, 0xc288c616aa7f3b59,
+    0x81ca63cf42fca3fd, 0x88d85ace36a2674b, 0xd056bd3792389e7,
+    0xe55c396c4e9dd32d, 0xbefb504571e6c0a6, 0x96ab32115e91e8cc,
+    0xbf8acb18de8f38d1, 0x66dae58801672606, 0x833b6017872317fb,
+    0xb87c16f2d1c92864, 0xdb766a74e58b669c, 0x89659f85c61417be,
+    0xc8daad856011ea0c, 0x76a4b565b6fe7eae, 0xa469d085f6237312,
+    0xaaf0365683a3e96c, 0x4dbb746f8424f7b8, 0x638755af4e4acc1,
+    0x3d7807f5bde64486, 0x17be6d8f5bbb7639, 0x903f0cd44dc35dc,
+    0x67b672eafdf1196c, 0xa676ff93ed4c82f1, 0x521d1004c5053d9d,
+    0x37ba9ad09ccc9202, 0x84e54d297aacfb51, 0xa0b4b776a143445,
+    0x820d471e20b348e,  0x1874383cb83d46dc, 0x97edeec7a1efe11c,
+    0xb330e50b1bdc42aa, 0x1dd91955ce70e032, 0xa514cdb88f2939d5,
+    0x2791233fd90db9d3, 0x7b670a4cc50f7a9b, 0x77c07d2a05c6dfa5,
+    0xe3778b6646d0a6fa, 0xb39c8eda47b56749, 0x933ed448addbef28,
+    0xaf846af6ab7d0bf4, 0xe5af208eb666e49,  0x5e6622f73534cd6a,
+    0x297daeca42ef5b6e, 0x862daef3d35539a6, 0xe68722498f8e1ea9,
+    0x981c53093dc0d572, 0xfa09b0bfbf86fbf5, 0x30b1e96166219f15,
+    0x70e7d466bdc4fb83, 0x5a66736e35f2a8e9, 0xcddb59d2b7c1baef,
+    0xd6c7d247d26d8996, 0xea4e39eac8de1ba3, 0x539c8bb19fa3aff2,
+    0x9f90e4c5fd508d8,  0xa34e5956fbaf3385, 0x2e2f8e151d3ef375,
+    0x173691e9b83faec1, 0xb85a8d56bf016379, 0x8382381267408ae3,
+    0xb90f901bbdc0096d, 0x7c6ad32933bcec65, 0x76bb5e2f2c8ad595,
+    0x390f851a6cf46d28, 0xc3e6064da1c2da72, 0xc52a0c101cfa5389,
+    0xd78eaf84a3fbc530, 0x3781b9e2288b997e, 0x73c2f6dea83d05c4,
+    0x4228e364c5b5ed7,  0x9d7a3edf0da43911, 0x8edcfeda24686756,
+    0x5e7667a7b7a9b3a1, 0x4c4f389fa143791d, 0xb08bc1023da7cddc,
+    0x7ab4be3ae529b1cc, 0x754e6132dbe74ff9, 0x71635442a839df45,
+    0x2f6fb1643fbe52de, 0x961e0a42cf7a8177, 0xf3b45d83d89ef2ea,
+    0xee3de4cf4a6e3e9b, 0xcd6848542c3295e7, 0xe4cee1664c78662f,
+    0x9947548b474c68c4, 0x25d73777a5ed8b0b, 0xc915b1d636b7fc,
+    0x21c2ba75d9b0d2da, 0x5f6b5dcf608a64a1, 0xdcf333255ff9570c,
+    0x633b922418ced4ee, 0xc136dde0b004b34a, 0x58cc83b05d4b2f5a,
+    0x5eb424dda28e42d2, 0x62df47369739cd98, 0xb4e0b42485e4ce17,
+    0x16e1f0c1f9a8d1e7, 0x8ec3916707560ebf, 0x62ba6e2df2cc9db3,
+    0xcbf9f4ff77d83a16, 0x78d9d7d07d2bbcc4, 0xef554ce1e02c41f4,
+    0x8d7581127eccf94d, 0xa9b53336cb3c8a05, 0x38c42c0bf45c4f91,
+    0x640893cdf4488863, 0x80ec34bc575ea568, 0x39f324f5b48eaa40,
+    0xe9d9ed1f8eff527f, 0x9224fc058cc5a214, 0xbaba00b04cfe7741,
+    0x309a9f120fcf52af, 0xa558f3ec65626212, 0x424bec8b7adabe2f,
+    0x41622513a6aea433, 0xb88da2d5324ca798, 0xd287733b245528a4,
+    0x9a44697e6d68aec3, 0x7b1093be2f49bb28, 0x50bbec632e3d8aad,
+    0x6cd90723e1ea8283, 0x897b9e7431b02bf3, 0x219efdcb338a7047,
+    0x3b0311f0a27c0656, 0xdb17bf91c0db96e7, 0x8cd4fd6b4e85a5b2,
+    0xfab071054ba6409d, 0x40d6fe831fa9dfd9, 0xaf358debad7d791e,
+    0xeb8d0e25a65e3e58, 0xbbcbd3df14e08580, 0xcf751f27ecdab2b,
+    0x2b4da14f2613d8f4
+};
+
+#endif /* ZSTD_LDM_GEARTAB_H */
index 36fff05..402a7e5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
+ * Copyright (c) Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -386,32 +386,32 @@ static U32 ZSTD_insertBt1(
     const BYTE* const dictEnd = dictBase + dictLimit;
     const BYTE* const prefixStart = base + dictLimit;
     const BYTE* match;
-    const U32 current = (U32)(ip-base);
-    const U32 btLow = btMask >= current ? 0 : current - btMask;
-    U32* smallerPtr = bt + 2*(current&btMask);
+    const U32 curr = (U32)(ip-base);
+    const U32 btLow = btMask >= curr ? 0 : curr - btMask;
+    U32* smallerPtr = bt + 2*(curr&btMask);
     U32* largerPtr  = smallerPtr + 1;
     U32 dummy32;   /* to be nullified at the end */
     U32 const windowLow = ms->window.lowLimit;
-    U32 matchEndIdx = current+8+1;
+    U32 matchEndIdx = curr+8+1;
     size_t bestLength = 8;
     U32 nbCompares = 1U << cParams->searchLog;
 #ifdef ZSTD_C_PREDICT
-    U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
-    U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
+    U32 predictedSmall = *(bt + 2*((curr-1)&btMask) + 0);
+    U32 predictedLarge = *(bt + 2*((curr-1)&btMask) + 1);
     predictedSmall += (predictedSmall>0);
     predictedLarge += (predictedLarge>0);
 #endif /* ZSTD_C_PREDICT */
 
-    DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current);
+    DEBUGLOG(8, "ZSTD_insertBt1 (%u)", curr);
 
     assert(ip <= iend-8);   /* required for h calculation */
-    hashTable[h] = current;   /* Update Hash Table */
+    hashTable[h] = curr;   /* Update Hash Table */
 
     assert(windowLow > 0);
     while (nbCompares-- && (matchIndex >= windowLow)) {
         U32* const nextPtr = bt + 2*(matchIndex & btMask);
         size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
-        assert(matchIndex < current);
+        assert(matchIndex < curr);
 
 #ifdef ZSTD_C_PREDICT   /* note : can create issues when hlog small <= 11 */
         const U32* predictPtr = bt + 2*((matchIndex-1) & btMask);   /* written this way, as bt is a roll buffer */
@@ -474,8 +474,8 @@ static U32 ZSTD_insertBt1(
     *smallerPtr = *largerPtr = 0;
     {   U32 positions = 0;
         if (bestLength > 384) positions = MIN(192, (U32)(bestLength - 384));   /* speed optimization */
-        assert(matchEndIdx > current + 8);
-        return MAX(positions, matchEndIdx - (current + 8));
+        assert(matchEndIdx > curr + 8);
+        return MAX(positions, matchEndIdx - (curr + 8));
     }
 }
 
@@ -519,7 +519,7 @@ U32 ZSTD_insertBtAndGetAllMatches (
     const ZSTD_compressionParameters* const cParams = &ms->cParams;
     U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
     const BYTE* const base = ms->window.base;
-    U32 const current = (U32)(ip-base);
+    U32 const curr = (U32)(ip-base);
     U32 const hashLog = cParams->hashLog;
     U32 const minMatch = (mls==3) ? 3 : 4;
     U32* const hashTable = ms->hashTable;
@@ -533,12 +533,12 @@ U32 ZSTD_insertBtAndGetAllMatches (
     U32 const dictLimit = ms->window.dictLimit;
     const BYTE* const dictEnd = dictBase + dictLimit;
     const BYTE* const prefixStart = base + dictLimit;
-    U32 const btLow = (btMask >= current) ? 0 : current - btMask;
-    U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog);
+    U32 const btLow = (btMask >= curr) ? 0 : curr - btMask;
+    U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog);
     U32 const matchLow = windowLow ? windowLow : 1;
-    U32* smallerPtr = bt + 2*(current&btMask);
-    U32* largerPtr  = bt + 2*(current&btMask) + 1;
-    U32 matchEndIdx = current+8+1;   /* farthest referenced position of any match => detects repetitive patterns */
+    U32* smallerPtr = bt + 2*(curr&btMask);
+    U32* largerPtr  = bt + 2*(curr&btMask) + 1;
+    U32 matchEndIdx = curr+8+1;   /* farthest referenced position of any match => detects repetitive patterns */
     U32 dummy32;   /* to be nullified at the end */
     U32 mnum = 0;
     U32 nbCompares = 1U << cParams->searchLog;
@@ -557,7 +557,7 @@ U32 ZSTD_insertBtAndGetAllMatches (
     U32         const dmsBtLow      = dictMode == ZSTD_dictMatchState && dmsBtMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - dmsBtMask : dmsLowLimit;
 
     size_t bestLength = lengthToBeat-1;
-    DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", current);
+    DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", curr);
 
     /* check repCode */
     assert(ll0 <= 1);   /* necessarily 1 or 0 */
@@ -565,29 +565,29 @@ U32 ZSTD_insertBtAndGetAllMatches (
         U32 repCode;
         for (repCode = ll0; repCode < lastR; repCode++) {
             U32 const repOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
-            U32 const repIndex = current - repOffset;
+            U32 const repIndex = curr - repOffset;
             U32 repLen = 0;
-            assert(current >= dictLimit);
-            if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) {  /* equivalent to `current > repIndex >= dictLimit` */
+            assert(curr >= dictLimit);
+            if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < curr-dictLimit) {  /* equivalent to `curr > repIndex >= dictLimit` */
                 /* We must validate the repcode offset because when we're using a dictionary the
                  * valid offset range shrinks when the dictionary goes out of bounds.
                  */
                 if ((repIndex >= windowLow) & (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch))) {
                     repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch;
                 }
-            } else {  /* repIndex < dictLimit || repIndex >= current */
+            } else {  /* repIndex < dictLimit || repIndex >= curr */
                 const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ?
                                              dmsBase + repIndex - dmsIndexDelta :
                                              dictBase + repIndex;
-                assert(current >= windowLow);
+                assert(curr >= windowLow);
                 if ( dictMode == ZSTD_extDict
-                  && ( ((repOffset-1) /*intentional overflow*/ < current - windowLow)  /* equivalent to `current > repIndex >= windowLow` */
+                  && ( ((repOffset-1) /*intentional overflow*/ < curr - windowLow)  /* equivalent to `curr > repIndex >= windowLow` */
                      & (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */)
                   && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
                     repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch;
                 }
                 if (dictMode == ZSTD_dictMatchState
-                  && ( ((repOffset-1) /*intentional overflow*/ < current - (dmsLowLimit + dmsIndexDelta))  /* equivalent to `current > repIndex >= dmsLowLimit` */
+                  && ( ((repOffset-1) /*intentional overflow*/ < curr - (dmsLowLimit + dmsIndexDelta))  /* equivalent to `curr > repIndex >= dmsLowLimit` */
                      & ((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */
                   && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
                     repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch;
@@ -609,7 +609,7 @@ U32 ZSTD_insertBtAndGetAllMatches (
     if ((mls == 3) /*static*/ && (bestLength < mls)) {
         U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, nextToUpdate3, ip);
         if ((matchIndex3 >= matchLow)
-          & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
+          & (curr - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
             size_t mlen;
             if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) {
                 const BYTE* const match = base + matchIndex3;
@@ -624,26 +624,26 @@ U32 ZSTD_insertBtAndGetAllMatches (
                 DEBUGLOG(8, "found small match with hlog3, of length %u",
                             (U32)mlen);
                 bestLength = mlen;
-                assert(current > matchIndex3);
+                assert(curr > matchIndex3);
                 assert(mnum==0);  /* no prior solution */
-                matches[0].off = (current - matchIndex3) + ZSTD_REP_MOVE;
+                matches[0].off = (curr - matchIndex3) + ZSTD_REP_MOVE;
                 matches[0].len = (U32)mlen;
                 mnum = 1;
                 if ( (mlen > sufficient_len) |
                      (ip+mlen == iLimit) ) {  /* best possible length */
-                    ms->nextToUpdate = current+1;  /* skip insertion */
+                    ms->nextToUpdate = curr+1;  /* skip insertion */
                     return 1;
         }   }   }
         /* no dictMatchState lookup: dicts don't have a populated HC3 table */
     }
 
-    hashTable[h] = current;   /* Update Hash Table */
+    hashTable[h] = curr;   /* Update Hash Table */
 
     while (nbCompares-- && (matchIndex >= matchLow)) {
         U32* const nextPtr = bt + 2*(matchIndex & btMask);
         const BYTE* match;
         size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
-        assert(current > matchIndex);
+        assert(curr > matchIndex);
 
         if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) {
             assert(matchIndex+matchLength >= dictLimit);  /* ensure the condition is correct when !extDict */
@@ -660,12 +660,12 @@ U32 ZSTD_insertBtAndGetAllMatches (
 
         if (matchLength > bestLength) {
             DEBUGLOG(8, "found match of length %u at distance %u (offCode=%u)",
-                    (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
+                    (U32)matchLength, curr - matchIndex, curr - matchIndex + ZSTD_REP_MOVE);
             assert(matchEndIdx > matchIndex);
             if (matchLength > matchEndIdx - matchIndex)
                 matchEndIdx = matchIndex + (U32)matchLength;
             bestLength = matchLength;
-            matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
+            matches[mnum].off = (curr - matchIndex) + ZSTD_REP_MOVE;
             matches[mnum].len = (U32)matchLength;
             mnum++;
             if ( (matchLength > ZSTD_OPT_NUM)
@@ -708,11 +708,11 @@ U32 ZSTD_insertBtAndGetAllMatches (
             if (matchLength > bestLength) {
                 matchIndex = dictMatchIndex + dmsIndexDelta;
                 DEBUGLOG(8, "found dms match of length %u at distance %u (offCode=%u)",
-                        (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
+                        (U32)matchLength, curr - matchIndex, curr - matchIndex + ZSTD_REP_MOVE);
                 if (matchLength > matchEndIdx - matchIndex)
                     matchEndIdx = matchIndex + (U32)matchLength;
                 bestLength = matchLength;
-                matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
+                matches[mnum].off = (curr - matchIndex) + ZSTD_REP_MOVE;
                 matches[mnum].len = (U32)matchLength;
                 mnum++;
                 if ( (matchLength > ZSTD_OPT_NUM)
@@ -733,7 +733,7 @@ U32 ZSTD_insertBtAndGetAllMatches (
         }
     }
 
-    assert(matchEndIdx > current+8);
+    assert(matchEndIdx > curr+8);
     ms->nextToUpdate = matchEndIdx - 8;  /* skip repetitive patterns */
     return mnum;
 }
@@ -764,6 +764,140 @@ FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches (
     }
 }
 
+/*************************
+*  LDM helper functions  *
+*************************/
+
+/* Struct containing info needed to make decision about ldm inclusion */
+typedef struct {
+    rawSeqStore_t seqStore;         /* External match candidates store for this block */
+    U32 startPosInBlock;            /* Start position of the current match candidate */
+    U32 endPosInBlock;              /* End position of the current match candidate */
+    U32 offset;                     /* Offset of the match candidate */
+} ZSTD_optLdm_t;
+
+/* ZSTD_optLdm_skipRawSeqStoreBytes():
+ * Moves forward in rawSeqStore by nbBytes, which will update the fields 'pos' and 'posInSequence'.
+ */
+static void ZSTD_optLdm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) {
+    U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes);
+    while (currPos && rawSeqStore->pos < rawSeqStore->size) {
+        rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos];
+        if (currPos >= currSeq.litLength + currSeq.matchLength) {
+            currPos -= currSeq.litLength + currSeq.matchLength;
+            rawSeqStore->pos++;
+        } else {
+            rawSeqStore->posInSequence = currPos;
+            break;
+        }
+    }
+    if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) {
+        rawSeqStore->posInSequence = 0;
+    }
+}
+
+/* ZSTD_opt_getNextMatchAndUpdateSeqStore():
+ * Calculates the beginning and end of the next match in the current block.
+ * Updates 'pos' and 'posInSequence' of the ldmSeqStore.
+ */
+static void ZSTD_opt_getNextMatchAndUpdateSeqStore(ZSTD_optLdm_t* optLdm, U32 currPosInBlock,
+                                                   U32 blockBytesRemaining) {
+    rawSeq currSeq;
+    U32 currBlockEndPos;
+    U32 literalsBytesRemaining;
+    U32 matchBytesRemaining;
+
+    /* Setting match end position to MAX to ensure we never use an LDM during this block */
+    if (optLdm->seqStore.size == 0 || optLdm->seqStore.pos >= optLdm->seqStore.size) {
+        optLdm->startPosInBlock = UINT_MAX;
+        optLdm->endPosInBlock = UINT_MAX;
+        return;
+    }
+    /* Calculate appropriate bytes left in matchLength and litLength after adjusting
+       based on ldmSeqStore->posInSequence */
+    currSeq = optLdm->seqStore.seq[optLdm->seqStore.pos];
+    assert(optLdm->seqStore.posInSequence <= currSeq.litLength + currSeq.matchLength);
+    currBlockEndPos = currPosInBlock + blockBytesRemaining;
+    literalsBytesRemaining = (optLdm->seqStore.posInSequence < currSeq.litLength) ?
+            currSeq.litLength - (U32)optLdm->seqStore.posInSequence :
+            0;
+    matchBytesRemaining = (literalsBytesRemaining == 0) ?
+            currSeq.matchLength - ((U32)optLdm->seqStore.posInSequence - currSeq.litLength) :
+            currSeq.matchLength;
+
+    /* If there are more literal bytes than bytes remaining in block, no ldm is possible */
+    if (literalsBytesRemaining >= blockBytesRemaining) {
+        optLdm->startPosInBlock = UINT_MAX;
+        optLdm->endPosInBlock = UINT_MAX;
+        ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, blockBytesRemaining);
+        return;
+    }
+
+    /* Matches may be < MINMATCH by this process. In that case, we will reject them
+       when we are deciding whether or not to add the ldm */
+    optLdm->startPosInBlock = currPosInBlock + literalsBytesRemaining;
+    optLdm->endPosInBlock = optLdm->startPosInBlock + matchBytesRemaining;
+    optLdm->offset = currSeq.offset;
+
+    if (optLdm->endPosInBlock > currBlockEndPos) {
+        /* Match ends after the block ends, we can't use the whole match */
+        optLdm->endPosInBlock = currBlockEndPos;
+        ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, currBlockEndPos - currPosInBlock);
+    } else {
+        /* Consume nb of bytes equal to size of sequence left */
+        ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, literalsBytesRemaining + matchBytesRemaining);
+    }
+}
+
+/* ZSTD_optLdm_maybeAddMatch():
+ * Adds a match if it's long enough, based on it's 'matchStartPosInBlock'
+ * and 'matchEndPosInBlock', into 'matches'. Maintains the correct ordering of 'matches'
+ */
+static void ZSTD_optLdm_maybeAddMatch(ZSTD_match_t* matches, U32* nbMatches,
+                                      ZSTD_optLdm_t* optLdm, U32 currPosInBlock) {
+    U32 posDiff = currPosInBlock - optLdm->startPosInBlock;
+    /* Note: ZSTD_match_t actually contains offCode and matchLength (before subtracting MINMATCH) */
+    U32 candidateMatchLength = optLdm->endPosInBlock - optLdm->startPosInBlock - posDiff;
+    U32 candidateOffCode = optLdm->offset + ZSTD_REP_MOVE;
+
+    /* Ensure that current block position is not outside of the match */
+    if (currPosInBlock < optLdm->startPosInBlock
+      || currPosInBlock >= optLdm->endPosInBlock
+      || candidateMatchLength < MINMATCH) {
+        return;
+    }
+
+    if (*nbMatches == 0 || ((candidateMatchLength > matches[*nbMatches-1].len) && *nbMatches < ZSTD_OPT_NUM)) {
+        DEBUGLOG(6, "ZSTD_optLdm_maybeAddMatch(): Adding ldm candidate match (offCode: %u matchLength %u) at block position=%u",
+                 candidateOffCode, candidateMatchLength, currPosInBlock);
+        matches[*nbMatches].len = candidateMatchLength;
+        matches[*nbMatches].off = candidateOffCode;
+        (*nbMatches)++;
+    }
+}
+
+/* ZSTD_optLdm_processMatchCandidate():
+ * Wrapper function to update ldm seq store and call ldm functions as necessary.
+ */
+static void ZSTD_optLdm_processMatchCandidate(ZSTD_optLdm_t* optLdm, ZSTD_match_t* matches, U32* nbMatches,
+                                              U32 currPosInBlock, U32 remainingBytes) {
+    if (optLdm->seqStore.size == 0 || optLdm->seqStore.pos >= optLdm->seqStore.size) {
+        return;
+    }
+
+    if (currPosInBlock >= optLdm->endPosInBlock) {
+        if (currPosInBlock > optLdm->endPosInBlock) {
+            /* The position at which ZSTD_optLdm_processMatchCandidate() is called is not necessarily
+             * at the end of a match from the ldm seq store, and will often be some bytes
+             * over beyond matchEndPosInBlock. As such, we need to correct for these "overshoots"
+             */
+            U32 posOvershoot = currPosInBlock - optLdm->endPosInBlock;
+            ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, posOvershoot);
+        } 
+        ZSTD_opt_getNextMatchAndUpdateSeqStore(optLdm, currPosInBlock, remainingBytes);
+    }
+    ZSTD_optLdm_maybeAddMatch(matches, nbMatches, optLdm, currPosInBlock);
+}
 
 /*-*******************************
 *  Optimal parser
@@ -817,6 +951,11 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
     ZSTD_optimal_t* const opt = optStatePtr->priceTable;
     ZSTD_match_t* const matches = optStatePtr->matchTable;
     ZSTD_optimal_t lastSequence;
+    ZSTD_optLdm_t optLdm;
+
+    optLdm.seqStore = ms->ldmSeqStore ? *ms->ldmSeqStore : kNullRawSeqStore;
+    optLdm.endPosInBlock = optLdm.startPosInBlock = optLdm.offset = 0;
+    ZSTD_opt_getNextMatchAndUpdateSeqStore(&optLdm, (U32)(ip-istart), (U32)(iend-ip));
 
     /* init */
     DEBUGLOG(5, "ZSTD_compressBlock_opt_generic: current=%u, prefix=%u, nextToUpdate=%u",
@@ -832,7 +971,9 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
         /* find first match */
         {   U32 const litlen = (U32)(ip - anchor);
             U32 const ll0 = !litlen;
-            U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, ip, iend, dictMode, rep, ll0, minMatch);
+            U32 nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, ip, iend, dictMode, rep, ll0, minMatch);
+            ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches,
+                                              (U32)(ip-istart), (U32)(iend - ip));
             if (!nbMatches) { ip++; continue; }
 
             /* initialize opt[0] */
@@ -925,9 +1066,9 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
             if (opt[cur].mlen != 0) {
                 U32 const prev = cur - opt[cur].mlen;
                 repcodes_t newReps = ZSTD_updateRep(opt[prev].rep, opt[cur].off, opt[cur].litlen==0);
-                memcpy(opt[cur].rep, &newReps, sizeof(repcodes_t));
+                ZSTD_memcpy(opt[cur].rep, &newReps, sizeof(repcodes_t));
             } else {
-                memcpy(opt[cur].rep, opt[cur - 1].rep, sizeof(repcodes_t));
+                ZSTD_memcpy(opt[cur].rep, opt[cur - 1].rep, sizeof(repcodes_t));
             }
 
             /* last match must start at a minimum distance of 8 from oend */
@@ -945,8 +1086,12 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
                 U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0;
                 U32 const previousPrice = opt[cur].price;
                 U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
-                U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, inr, iend, dictMode, opt[cur].rep, ll0, minMatch);
+                U32 nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, inr, iend, dictMode, opt[cur].rep, ll0, minMatch);
                 U32 matchNb;
+
+                ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches,
+                                                  (U32)(inr-istart), (U32)(iend-inr));
+
                 if (!nbMatches) {
                     DEBUGLOG(7, "rPos:%u : no match found", cur);
                     continue;
@@ -1010,9 +1155,9 @@ _shortestPath:   /* cur, last_pos, best_mlen, best_off have to be set */
          */
         if (lastSequence.mlen != 0) {
             repcodes_t reps = ZSTD_updateRep(opt[cur].rep, lastSequence.off, lastSequence.litlen==0);
-            memcpy(rep, &reps, sizeof(reps));
+            ZSTD_memcpy(rep, &reps, sizeof(reps));
         } else {
-            memcpy(rep, opt[cur].rep, sizeof(repcodes_t));
+            ZSTD_memcpy(rep, opt[cur].rep, sizeof(repcodes_t));
         }
 
         {   U32 const storeEnd = cur + 1;
@@ -1110,7 +1255,7 @@ ZSTD_initStats_ultra(ZSTD_matchState_t* ms,
                const void* src, size_t srcSize)
 {
     U32 tmpRep[ZSTD_REP_NUM];  /* updated rep codes will sink here */
-    memcpy(tmpRep, rep, sizeof(tmpRep));
+    ZSTD_memcpy(tmpRep, rep, sizeof(tmpRep));
 
     DEBUGLOG(4, "ZSTD_initStats_ultra (srcSize=%zu)", srcSize);
     assert(ms->opt.litLengthSum == 0);    /* first block */
@@ -1143,7 +1288,7 @@ size_t ZSTD_compressBlock_btultra2(
         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
         const void* src, size_t srcSize)
 {
-    U32 const current = (U32)((const BYTE*)src - ms->window.base);
+    U32 const curr = (U32)((const BYTE*)src - ms->window.base);
     DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize);
 
     /* 2-pass strategy:
@@ -1158,7 +1303,7 @@ size_t ZSTD_compressBlock_btultra2(
     if ( (ms->opt.litLengthSum==0)   /* first block */
       && (seqStore->sequences == seqStore->sequencesStart)  /* no ldm */
       && (ms->window.dictLimit == ms->window.lowLimit)   /* no dictionary */
-      && (current == ms->window.dictLimit)   /* start of frame, nothing already loaded nor skipped */
+      && (curr == ms->window.dictLimit)   /* start of frame, nothing already loaded nor skipped */
       && (srcSize > ZSTD_PREDEF_THRESHOLD)
       ) {
         ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize);
index 9aba8a9..627255f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
index 1e3c8fd..22aa3e1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -20,8 +20,7 @@
 
 
 /* ======   Dependencies   ====== */
-#include <string.h>      /* memcpy, memset */
-#include <limits.h>      /* INT_MAX, UINT_MAX */
+#include "../common/zstd_deps.h"   /* ZSTD_memcpy, ZSTD_memset, INT_MAX, UINT_MAX */
 #include "../common/mem.h"         /* MEM_STATIC */
 #include "../common/pool.h"        /* threadpool */
 #include "../common/threading.h"   /* mutex */
@@ -106,11 +105,11 @@ typedef struct ZSTDMT_bufferPool_s {
 static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned nbWorkers, ZSTD_customMem cMem)
 {
     unsigned const maxNbBuffers = 2*nbWorkers + 3;
-    ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_calloc(
+    ZSTDMT_bufferPool* const bufPool = (ZSTDMT_bufferPool*)ZSTD_customCalloc(
         sizeof(ZSTDMT_bufferPool) + (maxNbBuffers-1) * sizeof(buffer_t), cMem);
     if (bufPool==NULL) return NULL;
     if (ZSTD_pthread_mutex_init(&bufPool->poolMutex, NULL)) {
-        ZSTD_free(bufPool, cMem);
+        ZSTD_customFree(bufPool, cMem);
         return NULL;
     }
     bufPool->bufferSize = 64 KB;
@@ -127,10 +126,10 @@ static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool)
     if (!bufPool) return;   /* compatibility with free on NULL */
     for (u=0; u<bufPool->totalBuffers; u++) {
         DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->bTable[u].start);
-        ZSTD_free(bufPool->bTable[u].start, bufPool->cMem);
+        ZSTD_customFree(bufPool->bTable[u].start, bufPool->cMem);
     }
     ZSTD_pthread_mutex_destroy(&bufPool->poolMutex);
-    ZSTD_free(bufPool, bufPool->cMem);
+    ZSTD_customFree(bufPool, bufPool->cMem);
 }
 
 /* only works at initialization, not during compression */
@@ -201,13 +200,13 @@ static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
         }
         /* size conditions not respected : scratch this buffer, create new one */
         DEBUGLOG(5, "ZSTDMT_getBuffer: existing buffer does not meet size conditions => freeing");
-        ZSTD_free(buf.start, bufPool->cMem);
+        ZSTD_customFree(buf.start, bufPool->cMem);
     }
     ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
     /* create new buffer */
     DEBUGLOG(5, "ZSTDMT_getBuffer: create a new buffer");
     {   buffer_t buffer;
-        void* const start = ZSTD_malloc(bSize, bufPool->cMem);
+        void* const start = ZSTD_customMalloc(bSize, bufPool->cMem);
         buffer.start = start;   /* note : start can be NULL if malloc fails ! */
         buffer.capacity = (start==NULL) ? 0 : bSize;
         if (start==NULL) {
@@ -229,13 +228,13 @@ static buffer_t ZSTDMT_resizeBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buffer)
 {
     size_t const bSize = bufPool->bufferSize;
     if (buffer.capacity < bSize) {
-        void* const start = ZSTD_malloc(bSize, bufPool->cMem);
+        void* const start = ZSTD_customMalloc(bSize, bufPool->cMem);
         buffer_t newBuffer;
         newBuffer.start = start;
         newBuffer.capacity = start == NULL ? 0 : bSize;
         if (start != NULL) {
             assert(newBuffer.capacity >= buffer.capacity);
-            memcpy(newBuffer.start, buffer.start, buffer.capacity);
+            ZSTD_memcpy(newBuffer.start, buffer.start, buffer.capacity);
             DEBUGLOG(5, "ZSTDMT_resizeBuffer: created buffer of size %u", (U32)bSize);
             return newBuffer;
         }
@@ -261,14 +260,12 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
     ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
     /* Reached bufferPool capacity (should not happen) */
     DEBUGLOG(5, "ZSTDMT_releaseBuffer: pool capacity reached => freeing ");
-    ZSTD_free(buf.start, bufPool->cMem);
+    ZSTD_customFree(buf.start, bufPool->cMem);
 }
 
 
 /* =====   Seq Pool Wrapper   ====== */
 
-static rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0};
-
 typedef ZSTDMT_bufferPool ZSTDMT_seqPool;
 
 static size_t ZSTDMT_sizeof_seqPool(ZSTDMT_seqPool* seqPool)
@@ -278,7 +275,7 @@ static size_t ZSTDMT_sizeof_seqPool(ZSTDMT_seqPool* seqPool)
 
 static rawSeqStore_t bufferToSeq(buffer_t buffer)
 {
-    rawSeqStore_t seq = {NULL, 0, 0, 0};
+    rawSeqStore_t seq = kNullRawSeqStore;
     seq.seq = (rawSeq*)buffer.start;
     seq.capacity = buffer.capacity / sizeof(rawSeq);
     return seq;
@@ -354,7 +351,7 @@ static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool)
     for (cid=0; cid<pool->totalCCtx; cid++)
         ZSTD_freeCCtx(pool->cctx[cid]);  /* note : compatible with free on NULL */
     ZSTD_pthread_mutex_destroy(&pool->poolMutex);
-    ZSTD_free(pool, pool->cMem);
+    ZSTD_customFree(pool, pool->cMem);
 }
 
 /* ZSTDMT_createCCtxPool() :
@@ -362,12 +359,12 @@ static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool)
 static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(int nbWorkers,
                                               ZSTD_customMem cMem)
 {
-    ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_calloc(
+    ZSTDMT_CCtxPool* const cctxPool = (ZSTDMT_CCtxPool*) ZSTD_customCalloc(
         sizeof(ZSTDMT_CCtxPool) + (nbWorkers-1)*sizeof(ZSTD_CCtx*), cMem);
     assert(nbWorkers > 0);
     if (!cctxPool) return NULL;
     if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) {
-        ZSTD_free(cctxPool, cMem);
+        ZSTD_customFree(cctxPool, cMem);
         return NULL;
     }
     cctxPool->cMem = cMem;
@@ -475,10 +472,8 @@ ZSTDMT_serialState_reset(serialState_t* serialState,
         ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
         assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
         assert(params.ldmParams.hashRateLog < 32);
-        serialState->ldmState.hashPower =
-                ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
     } else {
-        memset(&params.ldmParams, 0, sizeof(params.ldmParams));
+        ZSTD_memset(&params.ldmParams, 0, sizeof(params.ldmParams));
     }
     serialState->nextJobID = 0;
     if (params.fParams.checksumFlag)
@@ -489,35 +484,35 @@ ZSTDMT_serialState_reset(serialState_t* serialState,
         size_t const hashSize = ((size_t)1 << hashLog) * sizeof(ldmEntry_t);
         unsigned const bucketLog =
             params.ldmParams.hashLog - params.ldmParams.bucketSizeLog;
-        size_t const bucketSize = (size_t)1 << bucketLog;
         unsigned const prevBucketLog =
             serialState->params.ldmParams.hashLog -
             serialState->params.ldmParams.bucketSizeLog;
+        size_t const numBuckets = (size_t)1 << bucketLog;
         /* Size the seq pool tables */
         ZSTDMT_setNbSeq(seqPool, ZSTD_ldm_getMaxNbSeq(params.ldmParams, jobSize));
         /* Reset the window */
         ZSTD_window_init(&serialState->ldmState.window);
         /* Resize tables and output space if necessary. */
         if (serialState->ldmState.hashTable == NULL || serialState->params.ldmParams.hashLog < hashLog) {
-            ZSTD_free(serialState->ldmState.hashTable, cMem);
-            serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_malloc(hashSize, cMem);
+            ZSTD_customFree(serialState->ldmState.hashTable, cMem);
+            serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_customMalloc(hashSize, cMem);
         }
         if (serialState->ldmState.bucketOffsets == NULL || prevBucketLog < bucketLog) {
-            ZSTD_free(serialState->ldmState.bucketOffsets, cMem);
-            serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_malloc(bucketSize, cMem);
+            ZSTD_customFree(serialState->ldmState.bucketOffsets, cMem);
+            serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_customMalloc(numBuckets, cMem);
         }
         if (!serialState->ldmState.hashTable || !serialState->ldmState.bucketOffsets)
             return 1;
         /* Zero the tables */
-        memset(serialState->ldmState.hashTable, 0, hashSize);
-        memset(serialState->ldmState.bucketOffsets, 0, bucketSize);
+        ZSTD_memset(serialState->ldmState.hashTable, 0, hashSize);
+        ZSTD_memset(serialState->ldmState.bucketOffsets, 0, numBuckets);
 
         /* Update window state and fill hash table with dict */
         serialState->ldmState.loadedDictEnd = 0;
         if (dictSize > 0) {
             if (dictContentType == ZSTD_dct_rawContent) {
                 BYTE const* const dictEnd = (const BYTE*)dict + dictSize;
-                ZSTD_window_update(&serialState->ldmState.window, dict, dictSize);
+                ZSTD_window_update(&serialState->ldmState.window, dict, dictSize, /* forceNonContiguous */ 0);
                 ZSTD_ldm_fillHashTable(&serialState->ldmState, (const BYTE*)dict, dictEnd, &params.ldmParams);
                 serialState->ldmState.loadedDictEnd = params.forceWindow ? 0 : (U32)(dictEnd - serialState->ldmState.window.base);
             } else {
@@ -537,7 +532,7 @@ ZSTDMT_serialState_reset(serialState_t* serialState,
 static int ZSTDMT_serialState_init(serialState_t* serialState)
 {
     int initError = 0;
-    memset(serialState, 0, sizeof(*serialState));
+    ZSTD_memset(serialState, 0, sizeof(*serialState));
     initError |= ZSTD_pthread_mutex_init(&serialState->mutex, NULL);
     initError |= ZSTD_pthread_cond_init(&serialState->cond, NULL);
     initError |= ZSTD_pthread_mutex_init(&serialState->ldmWindowMutex, NULL);
@@ -552,8 +547,8 @@ static void ZSTDMT_serialState_free(serialState_t* serialState)
     ZSTD_pthread_cond_destroy(&serialState->cond);
     ZSTD_pthread_mutex_destroy(&serialState->ldmWindowMutex);
     ZSTD_pthread_cond_destroy(&serialState->ldmWindowCond);
-    ZSTD_free(serialState->ldmState.hashTable, cMem);
-    ZSTD_free(serialState->ldmState.bucketOffsets, cMem);
+    ZSTD_customFree(serialState->ldmState.hashTable, cMem);
+    ZSTD_customFree(serialState->ldmState.bucketOffsets, cMem);
 }
 
 static void ZSTDMT_serialState_update(serialState_t* serialState,
@@ -574,7 +569,7 @@ static void ZSTDMT_serialState_update(serialState_t* serialState,
             assert(seqStore.seq != NULL && seqStore.pos == 0 &&
                    seqStore.size == 0 && seqStore.capacity > 0);
             assert(src.size <= serialState->params.jobSize);
-            ZSTD_window_update(&serialState->ldmState.window, src.start, src.size);
+            ZSTD_window_update(&serialState->ldmState.window, src.start, src.size, /* forceNonContiguous */ 0);
             error = ZSTD_ldm_generateSequences(
                 &serialState->ldmState, &seqStore,
                 &serialState->params.ldmParams, src.start, src.size);
@@ -686,6 +681,8 @@ static void ZSTDMT_compressionJob(void* jobDescription)
     if (job->jobID != 0) jobParams.fParams.checksumFlag = 0;
     /* Don't run LDM for the chunks, since we handle it externally */
     jobParams.ldmParams.enableLdm = 0;
+    /* Correct nbWorkers to 0. */
+    jobParams.nbWorkers = 0;
 
 
     /* init */
@@ -698,6 +695,10 @@ static void ZSTDMT_compressionJob(void* jobDescription)
         {   size_t const forceWindowError = ZSTD_CCtxParams_setParameter(&jobParams, ZSTD_c_forceMaxWindow, !job->firstJob);
             if (ZSTD_isError(forceWindowError)) JOB_ERROR(forceWindowError);
         }
+        if (!job->firstJob) {
+            size_t const err = ZSTD_CCtxParams_setParameter(&jobParams, ZSTD_c_deterministicRefPrefix, 0);
+            if (ZSTD_isError(err)) JOB_ERROR(err);
+        }
         {   size_t const initError = ZSTD_compressBegin_advanced_internal(cctx,
                                         job->prefix.start, job->prefix.size, ZSTD_dct_rawContent, /* load dictionary in "content-only" mode (no header analysis) */
                                         ZSTD_dtlm_fast,
@@ -753,6 +754,13 @@ static void ZSTDMT_compressionJob(void* jobDescription)
             if (ZSTD_isError(cSize)) JOB_ERROR(cSize);
             lastCBlockSize = cSize;
     }   }
+    if (!job->firstJob) {
+        /* Double check that we don't have an ext-dict, because then our
+         * repcode invalidation doesn't work.
+         */
+        assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window));
+    }
+    ZSTD_CCtx_trace(cctx, 0);
 
 _endJob:
     ZSTDMT_serialState_ensureFinished(job->serial, job->jobID, job->cSize);
@@ -820,7 +828,6 @@ struct ZSTDMT_CCtx_s {
     roundBuff_t roundBuff;
     serialState_t serial;
     rsyncState_t rsync;
-    unsigned singleBlockingThread;
     unsigned jobIDMask;
     unsigned doneJobID;
     unsigned nextJobID;
@@ -832,6 +839,7 @@ struct ZSTDMT_CCtx_s {
     ZSTD_customMem cMem;
     ZSTD_CDict* cdictLocal;
     const ZSTD_CDict* cdict;
+    unsigned providedFactory: 1;
 };
 
 static void ZSTDMT_freeJobsTable(ZSTDMT_jobDescription* jobTable, U32 nbJobs, ZSTD_customMem cMem)
@@ -842,7 +850,7 @@ static void ZSTDMT_freeJobsTable(ZSTDMT_jobDescription* jobTable, U32 nbJobs, ZS
         ZSTD_pthread_mutex_destroy(&jobTable[jobNb].job_mutex);
         ZSTD_pthread_cond_destroy(&jobTable[jobNb].job_cond);
     }
-    ZSTD_free(jobTable, cMem);
+    ZSTD_customFree(jobTable, cMem);
 }
 
 /* ZSTDMT_allocJobsTable()
@@ -854,7 +862,7 @@ static ZSTDMT_jobDescription* ZSTDMT_createJobsTable(U32* nbJobsPtr, ZSTD_custom
     U32 const nbJobs = 1 << nbJobsLog2;
     U32 jobNb;
     ZSTDMT_jobDescription* const jobTable = (ZSTDMT_jobDescription*)
-                ZSTD_calloc(nbJobs * sizeof(ZSTDMT_jobDescription), cMem);
+                ZSTD_customCalloc(nbJobs * sizeof(ZSTDMT_jobDescription), cMem);
     int initError = 0;
     if (jobTable==NULL) return NULL;
     *nbJobsPtr = nbJobs;
@@ -885,12 +893,12 @@ static size_t ZSTDMT_expandJobsTable (ZSTDMT_CCtx* mtctx, U32 nbWorkers) {
 
 /* ZSTDMT_CCtxParam_setNbWorkers():
  * Internal use only */
-size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers)
+static size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers)
 {
     return ZSTD_CCtxParams_setParameter(params, ZSTD_c_nbWorkers, (int)nbWorkers);
 }
 
-MEM_STATIC ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced_internal(unsigned nbWorkers, ZSTD_customMem cMem)
+MEM_STATIC ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced_internal(unsigned nbWorkers, ZSTD_customMem cMem, ZSTD_threadPool* pool)
 {
     ZSTDMT_CCtx* mtctx;
     U32 nbJobs = nbWorkers + 2;
@@ -903,12 +911,19 @@ MEM_STATIC ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced_internal(unsigned nbWorkers,
         /* invalid custom allocator */
         return NULL;
 
-    mtctx = (ZSTDMT_CCtx*) ZSTD_calloc(sizeof(ZSTDMT_CCtx), cMem);
+    mtctx = (ZSTDMT_CCtx*) ZSTD_customCalloc(sizeof(ZSTDMT_CCtx), cMem);
     if (!mtctx) return NULL;
     ZSTDMT_CCtxParam_setNbWorkers(&mtctx->params, nbWorkers);
     mtctx->cMem = cMem;
     mtctx->allJobsCompleted = 1;
-    mtctx->factory = POOL_create_advanced(nbWorkers, 0, cMem);
+    if (pool != NULL) {
+      mtctx->factory = pool;
+      mtctx->providedFactory = 1;
+    }
+    else {
+      mtctx->factory = POOL_create_advanced(nbWorkers, 0, cMem);
+      mtctx->providedFactory = 0;
+    }
     mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, cMem);
     assert(nbJobs > 0); assert((nbJobs & (nbJobs - 1)) == 0);  /* ensure nbJobs is a power of 2 */
     mtctx->jobIDMask = nbJobs - 1;
@@ -925,22 +940,18 @@ MEM_STATIC ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced_internal(unsigned nbWorkers,
     return mtctx;
 }
 
-ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, ZSTD_customMem cMem)
+ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, ZSTD_customMem cMem, ZSTD_threadPool* pool)
 {
 #ifdef ZSTD_MULTITHREAD
-    return ZSTDMT_createCCtx_advanced_internal(nbWorkers, cMem);
+    return ZSTDMT_createCCtx_advanced_internal(nbWorkers, cMem, pool);
 #else
     (void)nbWorkers;
     (void)cMem;
+    (void)pool;
     return NULL;
 #endif
 }
 
-ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers)
-{
-    return ZSTDMT_createCCtx_advanced(nbWorkers, ZSTD_defaultCMem);
-}
-
 
 /* ZSTDMT_releaseAllJobResources() :
  * note : ensure all workers are killed first ! */
@@ -957,7 +968,7 @@ static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx)
         ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff);
 
         /* Clear the job description, but keep the mutex/cond */
-        memset(&mtctx->jobs[jobID], 0, sizeof(mtctx->jobs[jobID]));
+        ZSTD_memset(&mtctx->jobs[jobID], 0, sizeof(mtctx->jobs[jobID]));
         mtctx->jobs[jobID].job_mutex = mutex;
         mtctx->jobs[jobID].job_cond = cond;
     }
@@ -984,7 +995,8 @@ static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* mtctx)
 size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx)
 {
     if (mtctx==NULL) return 0;   /* compatible with free on NULL */
-    POOL_free(mtctx->factory);   /* stop and free worker threads */
+    if (!mtctx->providedFactory)
+        POOL_free(mtctx->factory);   /* stop and free worker threads */
     ZSTDMT_releaseAllJobResources(mtctx);  /* release job resources into pools first */
     ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem);
     ZSTDMT_freeBufferPool(mtctx->bufPool);
@@ -993,8 +1005,8 @@ size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx)
     ZSTDMT_serialState_free(&mtctx->serial);
     ZSTD_freeCDict(mtctx->cdictLocal);
     if (mtctx->roundBuff.buffer)
-        ZSTD_free(mtctx->roundBuff.buffer, mtctx->cMem);
-    ZSTD_free(mtctx, mtctx->cMem);
+        ZSTD_customFree(mtctx->roundBuff.buffer, mtctx->cMem);
+    ZSTD_customFree(mtctx, mtctx->cMem);
     return 0;
 }
 
@@ -1011,65 +1023,6 @@ size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx)
             + mtctx->roundBuff.capacity;
 }
 
-/* Internal only */
-size_t
-ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params,
-                                   ZSTDMT_parameter parameter,
-                                   int value)
-{
-    DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter");
-    switch(parameter)
-    {
-    case ZSTDMT_p_jobSize :
-        DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter : set jobSize to %i", value);
-        return ZSTD_CCtxParams_setParameter(params, ZSTD_c_jobSize, value);
-    case ZSTDMT_p_overlapLog :
-        DEBUGLOG(4, "ZSTDMT_p_overlapLog : %i", value);
-        return ZSTD_CCtxParams_setParameter(params, ZSTD_c_overlapLog, value);
-    case ZSTDMT_p_rsyncable :
-        DEBUGLOG(4, "ZSTD_p_rsyncable : %i", value);
-        return ZSTD_CCtxParams_setParameter(params, ZSTD_c_rsyncable, value);
-    default :
-        return ERROR(parameter_unsupported);
-    }
-}
-
-size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int value)
-{
-    DEBUGLOG(4, "ZSTDMT_setMTCtxParameter");
-    return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value);
-}
-
-size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int* value)
-{
-    switch (parameter) {
-    case ZSTDMT_p_jobSize:
-        return ZSTD_CCtxParams_getParameter(&mtctx->params, ZSTD_c_jobSize, value);
-    case ZSTDMT_p_overlapLog:
-        return ZSTD_CCtxParams_getParameter(&mtctx->params, ZSTD_c_overlapLog, value);
-    case ZSTDMT_p_rsyncable:
-        return ZSTD_CCtxParams_getParameter(&mtctx->params, ZSTD_c_rsyncable, value);
-    default:
-        return ERROR(parameter_unsupported);
-    }
-}
-
-/* Sets parameters relevant to the compression job,
- * initializing others to default values. */
-static ZSTD_CCtx_params ZSTDMT_initJobCCtxParams(const ZSTD_CCtx_params* params)
-{
-    ZSTD_CCtx_params jobParams = *params;
-    /* Clear parameters related to multithreading */
-    jobParams.forceWindow = 0;
-    jobParams.nbWorkers = 0;
-    jobParams.jobSize = 0;
-    jobParams.overlapLog = 0;
-    jobParams.rsyncable = 0;
-    memset(&jobParams.ldmParams, 0, sizeof(ldmParams_t));
-    memset(&jobParams.customMem, 0, sizeof(ZSTD_customMem));
-    return jobParams;
-}
-
 
 /* ZSTDMT_resize() :
  * @return : error code if fails, 0 on success */
@@ -1098,7 +1051,7 @@ void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_p
     DEBUGLOG(5, "ZSTDMT_updateCParams_whileCompressing (level:%i)",
                 compressionLevel);
     mtctx->params.compressionLevel = compressionLevel;
-    {   ZSTD_compressionParameters cParams = ZSTD_getCParamsFromCCtxParams(cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, 0);
+    {   ZSTD_compressionParameters cParams = ZSTD_getCParamsFromCCtxParams(cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
         cParams.windowLog = saved_wlog;
         mtctx->params.cParams = cParams;
     }
@@ -1185,8 +1138,8 @@ static unsigned ZSTDMT_computeTargetJobLog(const ZSTD_CCtx_params* params)
     if (params->ldmParams.enableLdm) {
         /* In Long Range Mode, the windowLog is typically oversized.
          * In which case, it's preferable to determine the jobSize
-         * based on chainLog instead. */
-        jobLog = MAX(21, params->cParams.chainLog + 4);
+         * based on cycleLog instead. */
+        jobLog = MAX(21, ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy) + 3);
     } else {
         jobLog = MAX(20, params->cParams.windowLog + 2);
     }
@@ -1240,174 +1193,6 @@ static size_t ZSTDMT_computeOverlapSize(const ZSTD_CCtx_params* params)
     return (ovLog==0) ? 0 : (size_t)1 << ovLog;
 }
 
-static unsigned
-ZSTDMT_computeNbJobs(const ZSTD_CCtx_params* params, size_t srcSize, unsigned nbWorkers)
-{
-    assert(nbWorkers>0);
-    {   size_t const jobSizeTarget = (size_t)1 << ZSTDMT_computeTargetJobLog(params);
-        size_t const jobMaxSize = jobSizeTarget << 2;
-        size_t const passSizeMax = jobMaxSize * nbWorkers;
-        unsigned const multiplier = (unsigned)(srcSize / passSizeMax) + 1;
-        unsigned const nbJobsLarge = multiplier * nbWorkers;
-        unsigned const nbJobsMax = (unsigned)(srcSize / jobSizeTarget) + 1;
-        unsigned const nbJobsSmall = MIN(nbJobsMax, nbWorkers);
-        return (multiplier>1) ? nbJobsLarge : nbJobsSmall;
-}   }
-
-/* ZSTDMT_compress_advanced_internal() :
- * This is a blocking function : it will only give back control to caller after finishing its compression job.
- */
-static size_t
-ZSTDMT_compress_advanced_internal(
-                ZSTDMT_CCtx* mtctx,
-                void* dst, size_t dstCapacity,
-          const void* src, size_t srcSize,
-          const ZSTD_CDict* cdict,
-                ZSTD_CCtx_params params)
-{
-    ZSTD_CCtx_params const jobParams = ZSTDMT_initJobCCtxParams(&params);
-    size_t const overlapSize = ZSTDMT_computeOverlapSize(&params);
-    unsigned const nbJobs = ZSTDMT_computeNbJobs(&params, srcSize, params.nbWorkers);
-    size_t const proposedJobSize = (srcSize + (nbJobs-1)) / nbJobs;
-    size_t const avgJobSize = (((proposedJobSize-1) & 0x1FFFF) < 0x7FFF) ? proposedJobSize + 0xFFFF : proposedJobSize;   /* avoid too small last block */
-    const char* const srcStart = (const char*)src;
-    size_t remainingSrcSize = srcSize;
-    unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbJobs : (unsigned)(dstCapacity / ZSTD_compressBound(avgJobSize));  /* presumes avgJobSize >= 256 KB, which should be the case */
-    size_t frameStartPos = 0, dstBufferPos = 0;
-    assert(jobParams.nbWorkers == 0);
-    assert(mtctx->cctxPool->totalCCtx == params.nbWorkers);
-
-    params.jobSize = (U32)avgJobSize;
-    DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: nbJobs=%2u (rawSize=%u bytes; fixedSize=%u) ",
-                nbJobs, (U32)proposedJobSize, (U32)avgJobSize);
-
-    if ((nbJobs==1) | (params.nbWorkers<=1)) {   /* fallback to single-thread mode : this is a blocking invocation anyway */
-        ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0];
-        DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: fallback to single-thread mode");
-        if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, jobParams.fParams);
-        return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, NULL, 0, &jobParams);
-    }
-
-    assert(avgJobSize >= 256 KB);  /* condition for ZSTD_compressBound(A) + ZSTD_compressBound(B) <= ZSTD_compressBound(A+B), required to compress directly into Dst (no additional buffer) */
-    ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(avgJobSize) );
-    /* LDM doesn't even try to load the dictionary in single-ingestion mode */
-    if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, avgJobSize, NULL, 0, ZSTD_dct_auto))
-        return ERROR(memory_allocation);
-
-    FORWARD_IF_ERROR( ZSTDMT_expandJobsTable(mtctx, nbJobs) , "");  /* only expands if necessary */
-
-    {   unsigned u;
-        for (u=0; u<nbJobs; u++) {
-            size_t const jobSize = MIN(remainingSrcSize, avgJobSize);
-            size_t const dstBufferCapacity = ZSTD_compressBound(jobSize);
-            buffer_t const dstAsBuffer = { (char*)dst + dstBufferPos, dstBufferCapacity };
-            buffer_t const dstBuffer = u < compressWithinDst ? dstAsBuffer : g_nullBuffer;
-            size_t dictSize = u ? overlapSize : 0;
-
-            mtctx->jobs[u].prefix.start = srcStart + frameStartPos - dictSize;
-            mtctx->jobs[u].prefix.size = dictSize;
-            mtctx->jobs[u].src.start = srcStart + frameStartPos;
-            mtctx->jobs[u].src.size = jobSize; assert(jobSize > 0);  /* avoid job.src.size == 0 */
-            mtctx->jobs[u].consumed = 0;
-            mtctx->jobs[u].cSize = 0;
-            mtctx->jobs[u].cdict = (u==0) ? cdict : NULL;
-            mtctx->jobs[u].fullFrameSize = srcSize;
-            mtctx->jobs[u].params = jobParams;
-            /* do not calculate checksum within sections, but write it in header for first section */
-            mtctx->jobs[u].dstBuff = dstBuffer;
-            mtctx->jobs[u].cctxPool = mtctx->cctxPool;
-            mtctx->jobs[u].bufPool = mtctx->bufPool;
-            mtctx->jobs[u].seqPool = mtctx->seqPool;
-            mtctx->jobs[u].serial = &mtctx->serial;
-            mtctx->jobs[u].jobID = u;
-            mtctx->jobs[u].firstJob = (u==0);
-            mtctx->jobs[u].lastJob = (u==nbJobs-1);
-
-            DEBUGLOG(5, "ZSTDMT_compress_advanced_internal: posting job %u  (%u bytes)", u, (U32)jobSize);
-            DEBUG_PRINTHEX(6, mtctx->jobs[u].prefix.start, 12);
-            POOL_add(mtctx->factory, ZSTDMT_compressionJob, &mtctx->jobs[u]);
-
-            frameStartPos += jobSize;
-            dstBufferPos += dstBufferCapacity;
-            remainingSrcSize -= jobSize;
-    }   }
-
-    /* collect result */
-    {   size_t error = 0, dstPos = 0;
-        unsigned jobID;
-        for (jobID=0; jobID<nbJobs; jobID++) {
-            DEBUGLOG(5, "waiting for job %u ", jobID);
-            ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[jobID].job_mutex);
-            while (mtctx->jobs[jobID].consumed < mtctx->jobs[jobID].src.size) {
-                DEBUGLOG(5, "waiting for jobCompleted signal from job %u", jobID);
-                ZSTD_pthread_cond_wait(&mtctx->jobs[jobID].job_cond, &mtctx->jobs[jobID].job_mutex);
-            }
-            ZSTD_pthread_mutex_unlock(&mtctx->jobs[jobID].job_mutex);
-            DEBUGLOG(5, "ready to write job %u ", jobID);
-
-            {   size_t const cSize = mtctx->jobs[jobID].cSize;
-                if (ZSTD_isError(cSize)) error = cSize;
-                if ((!error) && (dstPos + cSize > dstCapacity)) error = ERROR(dstSize_tooSmall);
-                if (jobID) {   /* note : job 0 is written directly at dst, which is correct position */
-                    if (!error)
-                        memmove((char*)dst + dstPos, mtctx->jobs[jobID].dstBuff.start, cSize);  /* may overlap when job compressed within dst */
-                    if (jobID >= compressWithinDst) {  /* job compressed into its own buffer, which must be released */
-                        DEBUGLOG(5, "releasing buffer %u>=%u", jobID, compressWithinDst);
-                        ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff);
-                }   }
-                mtctx->jobs[jobID].dstBuff = g_nullBuffer;
-                mtctx->jobs[jobID].cSize = 0;
-                dstPos += cSize ;
-            }
-        }  /* for (jobID=0; jobID<nbJobs; jobID++) */
-
-        DEBUGLOG(4, "checksumFlag : %u ", params.fParams.checksumFlag);
-        if (params.fParams.checksumFlag) {
-            U32 const checksum = (U32)XXH64_digest(&mtctx->serial.xxhState);
-            if (dstPos + 4 > dstCapacity) {
-                error = ERROR(dstSize_tooSmall);
-            } else {
-                DEBUGLOG(4, "writing checksum : %08X \n", checksum);
-                MEM_writeLE32((char*)dst + dstPos, checksum);
-                dstPos += 4;
-        }   }
-
-        if (!error) DEBUGLOG(4, "compressed size : %u  ", (U32)dstPos);
-        return error ? error : dstPos;
-    }
-}
-
-size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
-                                void* dst, size_t dstCapacity,
-                          const void* src, size_t srcSize,
-                          const ZSTD_CDict* cdict,
-                                ZSTD_parameters params,
-                                int overlapLog)
-{
-    ZSTD_CCtx_params cctxParams = mtctx->params;
-    cctxParams.cParams = params.cParams;
-    cctxParams.fParams = params.fParams;
-    assert(ZSTD_OVERLAPLOG_MIN <= overlapLog && overlapLog <= ZSTD_OVERLAPLOG_MAX);
-    cctxParams.overlapLog = overlapLog;
-    return ZSTDMT_compress_advanced_internal(mtctx,
-                                             dst, dstCapacity,
-                                             src, srcSize,
-                                             cdict, cctxParams);
-}
-
-
-size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
-                           void* dst, size_t dstCapacity,
-                     const void* src, size_t srcSize,
-                           int compressionLevel)
-{
-    ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, 0);
-    int const overlapLog = ZSTDMT_overlapLog_default(params.cParams.strategy);
-    params.fParams.contentSizeFlag = 1;
-    return ZSTDMT_compress_advanced(mtctx, dst, dstCapacity, src, srcSize, NULL, params, overlapLog);
-}
-
-
 /* ====================================== */
 /* =======      Streaming API     ======= */
 /* ====================================== */
@@ -1432,16 +1217,6 @@ size_t ZSTDMT_initCStream_internal(
     if (params.jobSize != 0 && params.jobSize < ZSTDMT_JOBSIZE_MIN) params.jobSize = ZSTDMT_JOBSIZE_MIN;
     if (params.jobSize > (size_t)ZSTDMT_JOBSIZE_MAX) params.jobSize = (size_t)ZSTDMT_JOBSIZE_MAX;
 
-    mtctx->singleBlockingThread = (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN);  /* do not trigger multi-threading when srcSize is too small */
-    if (mtctx->singleBlockingThread) {
-        ZSTD_CCtx_params const singleThreadParams = ZSTDMT_initJobCCtxParams(&params);
-        DEBUGLOG(5, "ZSTDMT_initCStream_internal: switch to single blocking thread mode");
-        assert(singleThreadParams.nbWorkers == 0);
-        return ZSTD_initCStream_internal(mtctx->cctxPool->cctx[0],
-                                         dict, dictSize, cdict,
-                                         &singleThreadParams, pledgedSrcSize);
-    }
-
     DEBUGLOG(4, "ZSTDMT_initCStream_internal: %u workers", params.nbWorkers);
 
     if (mtctx->allJobsCompleted == 0) {   /* previous compression not correctly finished */
@@ -1475,9 +1250,8 @@ size_t ZSTDMT_initCStream_internal(
 
     if (params.rsyncable) {
         /* Aim for the targetsectionSize as the average job size. */
-        U32 const jobSizeMB = (U32)(mtctx->targetSectionSize >> 20);
-        U32 const rsyncBits = ZSTD_highbit32(jobSizeMB) + 20;
-        assert(jobSizeMB >= 1);
+        U32 const jobSizeKB = (U32)(mtctx->targetSectionSize >> 10);
+        U32 const rsyncBits = (assert(jobSizeKB >= 1), ZSTD_highbit32(jobSizeKB) + 10);
         DEBUGLOG(4, "rsyncLog = %u", rsyncBits);
         mtctx->rsync.hash = 0;
         mtctx->rsync.hitMask = (1ULL << rsyncBits) - 1;
@@ -1504,8 +1278,8 @@ size_t ZSTDMT_initCStream_internal(
         size_t const capacity = MAX(windowSize, sectionsSize) + slackSize;
         if (mtctx->roundBuff.capacity < capacity) {
             if (mtctx->roundBuff.buffer)
-                ZSTD_free(mtctx->roundBuff.buffer, mtctx->cMem);
-            mtctx->roundBuff.buffer = (BYTE*)ZSTD_malloc(capacity, mtctx->cMem);
+                ZSTD_customFree(mtctx->roundBuff.buffer, mtctx->cMem);
+            mtctx->roundBuff.buffer = (BYTE*)ZSTD_customMalloc(capacity, mtctx->cMem);
             if (mtctx->roundBuff.buffer == NULL) {
                 mtctx->roundBuff.capacity = 0;
                 return ERROR(memory_allocation);
@@ -1530,53 +1304,6 @@ size_t ZSTDMT_initCStream_internal(
     return 0;
 }
 
-size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
-                             const void* dict, size_t dictSize,
-                                   ZSTD_parameters params,
-                                   unsigned long long pledgedSrcSize)
-{
-    ZSTD_CCtx_params cctxParams = mtctx->params;  /* retrieve sticky params */
-    DEBUGLOG(4, "ZSTDMT_initCStream_advanced (pledgedSrcSize=%u)", (U32)pledgedSrcSize);
-    cctxParams.cParams = params.cParams;
-    cctxParams.fParams = params.fParams;
-    return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dct_auto, NULL,
-                                       cctxParams, pledgedSrcSize);
-}
-
-size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
-                               const ZSTD_CDict* cdict,
-                                     ZSTD_frameParameters fParams,
-                                     unsigned long long pledgedSrcSize)
-{
-    ZSTD_CCtx_params cctxParams = mtctx->params;
-    if (cdict==NULL) return ERROR(dictionary_wrong);   /* method incompatible with NULL cdict */
-    cctxParams.cParams = ZSTD_getCParamsFromCDict(cdict);
-    cctxParams.fParams = fParams;
-    return ZSTDMT_initCStream_internal(mtctx, NULL, 0 /*dictSize*/, ZSTD_dct_auto, cdict,
-                                       cctxParams, pledgedSrcSize);
-}
-
-
-/* ZSTDMT_resetCStream() :
- * pledgedSrcSize can be zero == unknown (for the time being)
- * prefer using ZSTD_CONTENTSIZE_UNKNOWN,
- * as `0` might mean "empty" in the future */
-size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize)
-{
-    if (!pledgedSrcSize) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
-    return ZSTDMT_initCStream_internal(mtctx, NULL, 0, ZSTD_dct_auto, 0, mtctx->params,
-                                       pledgedSrcSize);
-}
-
-size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel) {
-    ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
-    ZSTD_CCtx_params cctxParams = mtctx->params;   /* retrieve sticky params */
-    DEBUGLOG(4, "ZSTDMT_initCStream (cLevel=%i)", compressionLevel);
-    cctxParams.cParams = params.cParams;
-    cctxParams.fParams = params.fParams;
-    return ZSTDMT_initCStream_internal(mtctx, NULL, 0, ZSTD_dct_auto, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN);
-}
-
 
 /* ZSTDMT_writeLastEmptyBlock()
  * Write a single empty block with an end-of-frame to finish a frame.
@@ -1740,7 +1467,7 @@ static size_t ZSTDMT_flushProduced(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, u
             assert(cSize >= mtctx->jobs[wJobID].dstFlushed);
             assert(mtctx->jobs[wJobID].dstBuff.start != NULL);
             if (toFlush > 0) {
-                memcpy((char*)output->dst + output->pos,
+                ZSTD_memcpy((char*)output->dst + output->pos,
                     (const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed,
                     toFlush);
             }
@@ -1894,7 +1621,7 @@ static int ZSTDMT_tryGetInputRange(ZSTDMT_CCtx* mtctx)
             return 0;
         }
         ZSTDMT_waitForLdmComplete(mtctx, buffer);
-        memmove(start, mtctx->inBuff.prefix.start, prefixSize);
+        ZSTD_memmove(start, mtctx->inBuff.prefix.start, prefixSize);
         mtctx->inBuff.prefix.start = start;
         mtctx->roundBuff.pos = prefixSize;
     }
@@ -1968,6 +1695,16 @@ findSynchronizationPoint(ZSTDMT_CCtx const* mtctx, ZSTD_inBuffer const input)
         pos = 0;
         prev = (BYTE const*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled - RSYNC_LENGTH;
         hash = ZSTD_rollingHash_compute(prev, RSYNC_LENGTH);
+        if ((hash & hitMask) == hitMask) {
+            /* We're already at a sync point so don't load any more until
+             * we're able to flush this sync point.
+             * This likely happened because the job table was full so we
+             * couldn't add our job.
+             */
+            syncPoint.toLoad = 0;
+            syncPoint.flush = 1;
+            return syncPoint;
+        }
     } else {
         /* We don't have enough bytes buffered to initialize the hash, but
          * we know we have at least RSYNC_LENGTH bytes total.
@@ -2022,34 +1759,11 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
     assert(output->pos <= output->size);
     assert(input->pos  <= input->size);
 
-    if (mtctx->singleBlockingThread) {  /* delegate to single-thread (synchronous) */
-        return ZSTD_compressStream2(mtctx->cctxPool->cctx[0], output, input, endOp);
-    }
-
     if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) {
         /* current frame being ended. Only flush/end are allowed */
         return ERROR(stage_wrong);
     }
 
-    /* single-pass shortcut (note : synchronous-mode) */
-    if ( (!mtctx->params.rsyncable)   /* rsyncable mode is disabled */
-      && (mtctx->nextJobID == 0)      /* just started */
-      && (mtctx->inBuff.filled == 0)  /* nothing buffered */
-      && (!mtctx->jobReady)           /* no job already created */
-      && (endOp == ZSTD_e_end)        /* end order */
-      && (output->size - output->pos >= ZSTD_compressBound(input->size - input->pos)) ) { /* enough space in dst */
-        size_t const cSize = ZSTDMT_compress_advanced_internal(mtctx,
-                (char*)output->dst + output->pos, output->size - output->pos,
-                (const char*)input->src + input->pos, input->size - input->pos,
-                mtctx->cdict, mtctx->params);
-        if (ZSTD_isError(cSize)) return cSize;
-        input->pos = input->size;
-        output->pos += cSize;
-        mtctx->allJobsCompleted = 1;
-        mtctx->frameEnded = 1;
-        return 0;
-    }
-
     /* fill input buffer */
     if ( (!mtctx->jobReady)
       && (input->size > input->pos) ) {   /* support NULL input */
@@ -2072,13 +1786,21 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
             assert(mtctx->inBuff.buffer.capacity >= mtctx->targetSectionSize);
             DEBUGLOG(5, "ZSTDMT_compressStream_generic: adding %u bytes on top of %u to buffer of size %u",
                         (U32)syncPoint.toLoad, (U32)mtctx->inBuff.filled, (U32)mtctx->targetSectionSize);
-            memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, syncPoint.toLoad);
+            ZSTD_memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, syncPoint.toLoad);
             input->pos += syncPoint.toLoad;
             mtctx->inBuff.filled += syncPoint.toLoad;
             forwardInputProgress = syncPoint.toLoad>0;
         }
-        if ((input->pos < input->size) && (endOp == ZSTD_e_end))
-            endOp = ZSTD_e_flush;   /* can't end now : not all input consumed */
+    }
+    if ((input->pos < input->size) && (endOp == ZSTD_e_end)) {
+        /* Can't end yet because the input is not fully consumed.
+            * We are in one of these cases:
+            * - mtctx->inBuff is NULL & empty: we couldn't get an input buffer so don't create a new job.
+            * - We filled the input buffer: flush this job but don't end the frame.
+            * - We hit a synchronization point: flush this job but don't end the frame.
+            */
+        assert(mtctx->inBuff.filled == 0 || mtctx->inBuff.filled == mtctx->targetSectionSize || mtctx->params.rsyncable);
+        endOp = ZSTD_e_flush;
     }
 
     if ( (mtctx->jobReady)
@@ -2097,47 +1819,3 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
         return remainingToFlush;
     }
 }
-
-
-size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
-{
-    FORWARD_IF_ERROR( ZSTDMT_compressStream_generic(mtctx, output, input, ZSTD_e_continue) , "");
-
-    /* recommended next input size : fill current input buffer */
-    return mtctx->targetSectionSize - mtctx->inBuff.filled;   /* note : could be zero when input buffer is fully filled and no more availability to create new job */
-}
-
-
-static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_EndDirective endFrame)
-{
-    size_t const srcSize = mtctx->inBuff.filled;
-    DEBUGLOG(5, "ZSTDMT_flushStream_internal");
-
-    if ( mtctx->jobReady     /* one job ready for a worker to pick up */
-      || (srcSize > 0)       /* still some data within input buffer */
-      || ((endFrame==ZSTD_e_end) && !mtctx->frameEnded)) {  /* need a last 0-size block to end frame */
-           DEBUGLOG(5, "ZSTDMT_flushStream_internal : create a new job (%u bytes, end:%u)",
-                        (U32)srcSize, (U32)endFrame);
-        FORWARD_IF_ERROR( ZSTDMT_createCompressionJob(mtctx, srcSize, endFrame) , "");
-    }
-
-    /* check if there is any data available to flush */
-    return ZSTDMT_flushProduced(mtctx, output, 1 /* blockToFlush */, endFrame);
-}
-
-
-size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
-{
-    DEBUGLOG(5, "ZSTDMT_flushStream");
-    if (mtctx->singleBlockingThread)
-        return ZSTD_flushStream(mtctx->cctxPool->cctx[0], output);
-    return ZSTDMT_flushStream_internal(mtctx, output, ZSTD_e_flush);
-}
-
-size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
-{
-    DEBUGLOG(4, "ZSTDMT_endStream");
-    if (mtctx->singleBlockingThread)
-        return ZSTD_endStream(mtctx->cctxPool->cctx[0], output);
-    return ZSTDMT_flushStream_internal(mtctx, output, ZSTD_e_end);
-}
index 89914eb..2fee2ec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
 /* Note : This is an internal API.
  *        These APIs used to be exposed with ZSTDLIB_API,
  *        because it used to be the only way to invoke MT compression.
- *        Now, it's recommended to use ZSTD_compress2 and ZSTD_compressStream2()
- *        instead.
- *
- *        If you depend on these APIs and can't switch, then define
- *        ZSTD_LEGACY_MULTITHREADED_API when making the dynamic library.
- *        However, we may completely remove these functions in a future
- *        release, so please switch soon.
+ *        Now, you must use ZSTD_compress2 and ZSTD_compressStream2() instead.
  *
  *        This API requires ZSTD_MULTITHREAD to be defined during compilation,
  *        otherwise ZSTDMT_createCCtx*() will fail.
  */
 
-#ifdef ZSTD_LEGACY_MULTITHREADED_API
-#  define ZSTDMT_API ZSTDLIB_API
-#else
-#  define ZSTDMT_API
-#endif
-
 /* ===   Dependencies   === */
-#include <stddef.h>                /* size_t */
+#include "../common/zstd_deps.h"   /* size_t */
 #define ZSTD_STATIC_LINKING_ONLY   /* ZSTD_parameters */
 #include "../zstd.h"            /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTDLIB_API */
 
 
 /* ===   Constants   === */
-#ifndef ZSTDMT_NBWORKERS_MAX
-#  define ZSTDMT_NBWORKERS_MAX 200
+#ifndef ZSTDMT_NBWORKERS_MAX /* a different value can be selected at compile time */
+#  define ZSTDMT_NBWORKERS_MAX ((sizeof(void*)==4) /*32-bit*/ ? 64 : 256)
 #endif
-#ifndef ZSTDMT_JOBSIZE_MIN
-#  define ZSTDMT_JOBSIZE_MIN (1 MB)
+#ifndef ZSTDMT_JOBSIZE_MIN   /* a different value can be selected at compile time */
+#  define ZSTDMT_JOBSIZE_MIN (512 KB)
 #endif
 #define ZSTDMT_JOBLOG_MAX   (MEM_32bits() ? 29 : 30)
 #define ZSTDMT_JOBSIZE_MAX  (MEM_32bits() ? (512 MB) : (1024 MB))
 
 
+/* ========================================================
+ * ===  Private interface, for use by ZSTD_compress.c   ===
+ * ===  Not exposed in libzstd. Never invoke directly   ===
+ * ======================================================== */
+
 /* ===   Memory management   === */
 typedef struct ZSTDMT_CCtx_s ZSTDMT_CCtx;
 /* Requires ZSTD_MULTITHREAD to be defined during compilation, otherwise it will return NULL. */
-ZSTDMT_API ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbWorkers);
-/* Requires ZSTD_MULTITHREAD to be defined during compilation, otherwise it will return NULL. */
-ZSTDMT_API ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers,
-                                                    ZSTD_customMem cMem);
-ZSTDMT_API size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx);
-
-ZSTDMT_API size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx);
-
-
-/* ===   Simple one-pass compression function   === */
-
-ZSTDMT_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
-                                       void* dst, size_t dstCapacity,
-                                 const void* src, size_t srcSize,
-                                       int compressionLevel);
-
+ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers,
+                                        ZSTD_customMem cMem,
+                                       ZSTD_threadPool *pool);
+size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx);
 
+size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx);
 
 /* ===   Streaming functions   === */
 
-ZSTDMT_API size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel);
-ZSTDMT_API size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize);  /**< if srcSize is not known at reset time, use ZSTD_CONTENTSIZE_UNKNOWN. Note: for compatibility with older programs, 0 means the same as ZSTD_CONTENTSIZE_UNKNOWN, but it will change in the future to mean "empty" */
-
-ZSTDMT_API size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx);
-ZSTDMT_API size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
-
-ZSTDMT_API size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output);   /**< @return : 0 == all flushed; >0 : still some data to be flushed; or an error code (ZSTD_isError()) */
-ZSTDMT_API size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output);     /**< @return : 0 == all flushed; >0 : still some data to be flushed; or an error code (ZSTD_isError()) */
-
-
-/* ===   Advanced functions and parameters  === */
-
-ZSTDMT_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
-                                          void* dst, size_t dstCapacity,
-                                    const void* src, size_t srcSize,
-                                    const ZSTD_CDict* cdict,
-                                          ZSTD_parameters params,
-                                          int overlapLog);
-
-ZSTDMT_API size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
-                                        const void* dict, size_t dictSize,   /* dict can be released after init, a local copy is preserved within zcs */
-                                        ZSTD_parameters params,
-                                        unsigned long long pledgedSrcSize);  /* pledgedSrcSize is optional and can be zero == unknown */
-
-ZSTDMT_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
-                                        const ZSTD_CDict* cdict,
-                                        ZSTD_frameParameters fparams,
-                                        unsigned long long pledgedSrcSize);  /* note : zero means empty */
-
-/* ZSTDMT_parameter :
- * List of parameters that can be set using ZSTDMT_setMTCtxParameter() */
-typedef enum {
-    ZSTDMT_p_jobSize,     /* Each job is compressed in parallel. By default, this value is dynamically determined depending on compression parameters. Can be set explicitly here. */
-    ZSTDMT_p_overlapLog,  /* Each job may reload a part of previous job to enhance compression ratio; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window. This is a "sticky" parameter : its value will be re-used on next compression job */
-    ZSTDMT_p_rsyncable    /* Enables rsyncable mode. */
-} ZSTDMT_parameter;
-
-/* ZSTDMT_setMTCtxParameter() :
- * allow setting individual parameters, one at a time, among a list of enums defined in ZSTDMT_parameter.
- * The function must be called typically after ZSTD_createCCtx() but __before ZSTDMT_init*() !__
- * Parameters not explicitly reset by ZSTDMT_init*() remain the same in consecutive compression sessions.
- * @return : 0, or an error code (which can be tested using ZSTD_isError()) */
-ZSTDMT_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int value);
-
-/* ZSTDMT_getMTCtxParameter() :
- * Query the ZSTDMT_CCtx for a parameter value.
- * @return : 0, or an error code (which can be tested using ZSTD_isError()) */
-ZSTDMT_API size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, int* value);
+size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx);
 
+/*! ZSTDMT_initCStream_internal() :
+ *  Private use only. Init streaming operation.
+ *  expects params to be valid.
+ *  must receive dict, or cdict, or none, but not both.
+ *  @return : 0, or an error code */
+size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
+                    const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType,
+                    const ZSTD_CDict* cdict,
+                    ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
 
 /*! ZSTDMT_compressStream_generic() :
  *  Combines ZSTDMT_compressStream() with optional ZSTDMT_flushStream() or ZSTDMT_endStream()
@@ -134,16 +78,10 @@ ZSTDMT_API size_t ZSTDMT_getMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter
  *           0 if fully flushed
  *           or an error code
  *  note : needs to be init using any ZSTD_initCStream*() variant */
-ZSTDMT_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
-                                                ZSTD_outBuffer* output,
-                                                ZSTD_inBuffer* input,
-                                                ZSTD_EndDirective endOp);
-
-
-/* ========================================================
- * ===  Private interface, for use by ZSTD_compress.c   ===
- * ===  Not exposed in libzstd. Never invoke directly   ===
- * ======================================================== */
+size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
+                                     ZSTD_outBuffer* output,
+                                     ZSTD_inBuffer* input,
+                                     ZSTD_EndDirective endOp);
 
  /*! ZSTDMT_toFlushNow()
   *  Tell how many bytes are ready to be flushed immediately.
@@ -153,15 +91,6 @@ ZSTDMT_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
   *  therefore flushing is limited by speed of oldest job. */
 size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx);
 
-/*! ZSTDMT_CCtxParam_setMTCtxParameter()
- *  like ZSTDMT_setMTCtxParameter(), but into a ZSTD_CCtx_Params */
-size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, int value);
-
-/*! ZSTDMT_CCtxParam_setNbWorkers()
- *  Set nbWorkers, and clamp it.
- *  Also reset jobSize and overlapLog */
-size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers);
-
 /*! ZSTDMT_updateCParams_whileCompressing() :
  *  Updates only a selected set of compression parameters, to remain compatible with current frame.
  *  New parameters will be applied to next compression job. */
@@ -174,17 +103,6 @@ void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_p
 ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx);
 
 
-/*! ZSTDMT_initCStream_internal() :
- *  Private use only. Init streaming operation.
- *  expects params to be valid.
- *  must receive dict, or cdict, or none, but not both.
- *  @return : 0, or an error code */
-size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
-                    const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType,
-                    const ZSTD_CDict* cdict,
-                    ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
-
-
 #if defined (__cplusplus)
 }
 #endif
index 68293a1..b93c9a0 100644 (file)
@@ -1,7 +1,7 @@
 /* ******************************************************************
  * huff0 huffman decoder,
  * part of Finite State Entropy library
- * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  *
  *  You can contact the author at :
  *  - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
@@ -15,7 +15,7 @@
 /* **************************************************************
 *  Dependencies
 ****************************************************************/
-#include <string.h>     /* memcpy, memset */
+#include "../common/zstd_deps.h"  /* ZSTD_memcpy, ZSTD_memset */
 #include "../common/compiler.h"
 #include "../common/bitstream.h"  /* BIT_* */
 #include "../common/fse.h"        /* to compress headers */
@@ -103,7 +103,7 @@ typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved;
 static DTableDesc HUF_getDTableDesc(const HUF_DTable* table)
 {
     DTableDesc dtd;
-    memcpy(&dtd, table, sizeof(dtd));
+    ZSTD_memcpy(&dtd, table, sizeof(dtd));
     return dtd;
 }
 
@@ -115,29 +115,51 @@ static DTableDesc HUF_getDTableDesc(const HUF_DTable* table)
 /*-***************************/
 typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX1;   /* single-symbol decoding */
 
+/**
+ * Packs 4 HUF_DEltX1 structs into a U64. This is used to lay down 4 entries at
+ * a time.
+ */
+static U64 HUF_DEltX1_set4(BYTE symbol, BYTE nbBits) {
+    U64 D4;
+    if (MEM_isLittleEndian()) {
+        D4 = symbol + (nbBits << 8);
+    } else {
+        D4 = (symbol << 8) + nbBits;
+    }
+    D4 *= 0x0001000100010001ULL;
+    return D4;
+}
+
+typedef struct {
+        U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1];
+        U32 rankStart[HUF_TABLELOG_ABSOLUTEMAX + 1];
+        U32 statsWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32];
+        BYTE symbols[HUF_SYMBOLVALUE_MAX + 1];
+        BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1];
+} HUF_ReadDTableX1_Workspace;
+
+
 size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize)
 {
+    return HUF_readDTableX1_wksp_bmi2(DTable, src, srcSize, workSpace, wkspSize, /* bmi2 */ 0);
+}
+
+size_t HUF_readDTableX1_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2)
+{
     U32 tableLog = 0;
     U32 nbSymbols = 0;
     size_t iSize;
     void* const dtPtr = DTable + 1;
     HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr;
+    HUF_ReadDTableX1_Workspace* wksp = (HUF_ReadDTableX1_Workspace*)workSpace;
 
-    U32* rankVal;
-    BYTE* huffWeight;
-    size_t spaceUsed32 = 0;
-
-    rankVal = (U32 *)workSpace + spaceUsed32;
-    spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1;
-    huffWeight = (BYTE *)((U32 *)workSpace + spaceUsed32);
-    spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
-
-    if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
+    DEBUG_STATIC_ASSERT(HUF_DECOMPRESS_WORKSPACE_SIZE >= sizeof(*wksp));
+    if (sizeof(*wksp) > wkspSize) return ERROR(tableLog_tooLarge);
 
     DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
-    /* memset(huffWeight, 0, sizeof(huffWeight)); */   /* is not necessary, even though some analyzer complain ... */
+    /* ZSTD_memset(huffWeight, 0, sizeof(huffWeight)); */   /* is not necessary, even though some analyzer complain ... */
 
-    iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize);
+    iSize = HUF_readStats_wksp(wksp->huffWeight, HUF_SYMBOLVALUE_MAX + 1, wksp->rankVal, &nbSymbols, &tableLog, src, srcSize, wksp->statsWksp, sizeof(wksp->statsWksp), bmi2);
     if (HUF_isError(iSize)) return iSize;
 
     /* Table header */
@@ -145,52 +167,117 @@ size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize
         if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge);   /* DTable too small, Huffman tree cannot fit in */
         dtd.tableType = 0;
         dtd.tableLog = (BYTE)tableLog;
-        memcpy(DTable, &dtd, sizeof(dtd));
+        ZSTD_memcpy(DTable, &dtd, sizeof(dtd));
     }
 
-    /* Calculate starting value for each rank */
-    {   U32 n, nextRankStart = 0;
-        for (n=1; n<tableLog+1; n++) {
-            U32 const current = nextRankStart;
-            nextRankStart += (rankVal[n] << (n-1));
-            rankVal[n] = current;
-    }   }
+    /* Compute symbols and rankStart given rankVal:
+     *
+     * rankVal already contains the number of values of each weight.
+     *
+     * symbols contains the symbols ordered by weight. First are the rankVal[0]
+     * weight 0 symbols, followed by the rankVal[1] weight 1 symbols, and so on.
+     * symbols[0] is filled (but unused) to avoid a branch.
+     *
+     * rankStart contains the offset where each rank belongs in the DTable.
+     * rankStart[0] is not filled because there are no entries in the table for
+     * weight 0.
+     */
+    {
+        int n;
+        int nextRankStart = 0;
+        int const unroll = 4;
+        int const nLimit = (int)nbSymbols - unroll + 1;
+        for (n=0; n<(int)tableLog+1; n++) {
+            U32 const curr = nextRankStart;
+            nextRankStart += wksp->rankVal[n];
+            wksp->rankStart[n] = curr;
+        }
+        for (n=0; n < nLimit; n += unroll) {
+            int u;
+            for (u=0; u < unroll; ++u) {
+                size_t const w = wksp->huffWeight[n+u];
+                wksp->symbols[wksp->rankStart[w]++] = (BYTE)(n+u);
+            }
+        }
+        for (; n < (int)nbSymbols; ++n) {
+            size_t const w = wksp->huffWeight[n];
+            wksp->symbols[wksp->rankStart[w]++] = (BYTE)n;
+        }
+    }
 
-    /* fill DTable */
-    {   U32 n;
-        size_t const nEnd = nbSymbols;
-        for (n=0; n<nEnd; n++) {
-            size_t const w = huffWeight[n];
-            size_t const length = (1 << w) >> 1;
-            size_t const uStart = rankVal[w];
-            size_t const uEnd = uStart + length;
-            size_t u;
-            HUF_DEltX1 D;
-            D.byte = (BYTE)n;
-            D.nbBits = (BYTE)(tableLog + 1 - w);
-            rankVal[w] = (U32)uEnd;
-            if (length < 4) {
-                /* Use length in the loop bound so the compiler knows it is short. */
-                for (u = 0; u < length; ++u)
-                    dt[uStart + u] = D;
-            } else {
-                /* Unroll the loop 4 times, we know it is a power of 2. */
-                for (u = uStart; u < uEnd; u += 4) {
-                    dt[u + 0] = D;
-                    dt[u + 1] = D;
-                    dt[u + 2] = D;
-                    dt[u + 3] = D;
-    }   }   }   }
+    /* fill DTable
+     * We fill all entries of each weight in order.
+     * That way length is a constant for each iteration of the outter loop.
+     * We can switch based on the length to a different inner loop which is
+     * optimized for that particular case.
+     */
+    {
+        U32 w;
+        int symbol=wksp->rankVal[0];
+        int rankStart=0;
+        for (w=1; w<tableLog+1; ++w) {
+            int const symbolCount = wksp->rankVal[w];
+            int const length = (1 << w) >> 1;
+            int uStart = rankStart;
+            BYTE const nbBits = (BYTE)(tableLog + 1 - w);
+            int s;
+            int u;
+            switch (length) {
+            case 1:
+                for (s=0; s<symbolCount; ++s) {
+                    HUF_DEltX1 D;
+                    D.byte = wksp->symbols[symbol + s];
+                    D.nbBits = nbBits;
+                    dt[uStart] = D;
+                    uStart += 1;
+                }
+                break;
+            case 2:
+                for (s=0; s<symbolCount; ++s) {
+                    HUF_DEltX1 D;
+                    D.byte = wksp->symbols[symbol + s];
+                    D.nbBits = nbBits;
+                    dt[uStart+0] = D;
+                    dt[uStart+1] = D;
+                    uStart += 2;
+                }
+                break;
+            case 4:
+                for (s=0; s<symbolCount; ++s) {
+                    U64 const D4 = HUF_DEltX1_set4(wksp->symbols[symbol + s], nbBits);
+                    MEM_write64(dt + uStart, D4);
+                    uStart += 4;
+                }
+                break;
+            case 8:
+                for (s=0; s<symbolCount; ++s) {
+                    U64 const D4 = HUF_DEltX1_set4(wksp->symbols[symbol + s], nbBits);
+                    MEM_write64(dt + uStart, D4);
+                    MEM_write64(dt + uStart + 4, D4);
+                    uStart += 8;
+                }
+                break;
+            default:
+                for (s=0; s<symbolCount; ++s) {
+                    U64 const D4 = HUF_DEltX1_set4(wksp->symbols[symbol + s], nbBits);
+                    for (u=0; u < length; u += 16) {
+                        MEM_write64(dt + uStart + u + 0, D4);
+                        MEM_write64(dt + uStart + u + 4, D4);
+                        MEM_write64(dt + uStart + u + 8, D4);
+                        MEM_write64(dt + uStart + u + 12, D4);
+                    }
+                    assert(u == length);
+                    uStart += length;
+                }
+                break;
+            }
+            symbol += symbolCount;
+            rankStart += symbolCount * length;
+        }
+    }
     return iSize;
 }
 
-size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize)
-{
-    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
-    return HUF_readDTableX1_wksp(DTable, src, srcSize,
-                                 workSpace, sizeof(workSpace));
-}
-
 FORCE_INLINE_TEMPLATE BYTE
 HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog)
 {
@@ -389,20 +476,6 @@ size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
 }
 
 
-size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
-                              const void* cSrc, size_t cSrcSize)
-{
-    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
-    return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
-                                       workSpace, sizeof(workSpace));
-}
-
-size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
-    HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
-    return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize);
-}
-
 size_t HUF_decompress4X1_usingDTable(
           void* dst,  size_t dstSize,
     const void* cSrc, size_t cSrcSize,
@@ -419,8 +492,7 @@ static size_t HUF_decompress4X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size
 {
     const BYTE* ip = (const BYTE*) cSrc;
 
-    size_t const hSize = HUF_readDTableX1_wksp (dctx, cSrc, cSrcSize,
-                                                workSpace, wkspSize);
+    size_t const hSize = HUF_readDTableX1_wksp_bmi2(dctx, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
     if (HUF_isError(hSize)) return hSize;
     if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
     ip += hSize; cSrcSize -= hSize;
@@ -436,18 +508,6 @@ size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
 }
 
 
-size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
-    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
-    return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
-                                       workSpace, sizeof(workSpace));
-}
-size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
-    HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
-    return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
-}
-
 #endif /* HUF_FORCE_DECOMPRESS_X2 */
 
 
@@ -468,13 +528,15 @@ typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX];
 static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 consumed,
                            const U32* rankValOrigin, const int minWeight,
                            const sortedSymbol_t* sortedSymbols, const U32 sortedListSize,
-                           U32 nbBitsBaseline, U16 baseSeq)
+                           U32 nbBitsBaseline, U16 baseSeq, U32* wksp, size_t wkspSize)
 {
     HUF_DEltX2 DElt;
-    U32 rankVal[HUF_TABLELOG_MAX + 1];
+    U32* rankVal = wksp;
 
+    assert(wkspSize >= HUF_TABLELOG_MAX + 1);
+    (void)wkspSize;
     /* get pre-calculated rankVal */
-    memcpy(rankVal, rankValOrigin, sizeof(rankVal));
+    ZSTD_memcpy(rankVal, rankValOrigin, sizeof(U32) * (HUF_TABLELOG_MAX + 1));
 
     /* fill skipped values */
     if (minWeight>1) {
@@ -509,14 +571,18 @@ static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 co
 static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog,
                            const sortedSymbol_t* sortedList, const U32 sortedListSize,
                            const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight,
-                           const U32 nbBitsBaseline)
+                           const U32 nbBitsBaseline, U32* wksp, size_t wkspSize)
 {
-    U32 rankVal[HUF_TABLELOG_MAX + 1];
+    U32* rankVal = wksp;
     const int scaleLog = nbBitsBaseline - targetLog;   /* note : targetLog >= srcLog, hence scaleLog <= 1 */
     const U32 minBits  = nbBitsBaseline - maxWeight;
     U32 s;
 
-    memcpy(rankVal, rankValOrigin, sizeof(rankVal));
+    assert(wkspSize >= HUF_TABLELOG_MAX + 1);
+    wksp += HUF_TABLELOG_MAX + 1;
+    wkspSize -= HUF_TABLELOG_MAX + 1;
+
+    ZSTD_memcpy(rankVal, rankValOrigin, sizeof(U32) * (HUF_TABLELOG_MAX + 1));
 
     /* fill DTable */
     for (s=0; s<sortedListSize; s++) {
@@ -534,7 +600,7 @@ static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog,
             HUF_fillDTableX2Level2(DTable+start, targetLog-nbBits, nbBits,
                            rankValOrigin[nbBits], minWeight,
                            sortedList+sortedRank, sortedListSize-sortedRank,
-                           nbBitsBaseline, symbol);
+                           nbBitsBaseline, symbol, wksp, wkspSize);
         } else {
             HUF_DEltX2 DElt;
             MEM_writeLE16(&(DElt.sequence), symbol);
@@ -548,6 +614,15 @@ static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog,
     }
 }
 
+typedef struct {
+    rankValCol_t rankVal[HUF_TABLELOG_MAX];
+    U32 rankStats[HUF_TABLELOG_MAX + 1];
+    U32 rankStart0[HUF_TABLELOG_MAX + 2];
+    sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1];
+    BYTE weightList[HUF_SYMBOLVALUE_MAX + 1];
+    U32 calleeWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32];
+} HUF_ReadDTableX2_Workspace;
+
 size_t HUF_readDTableX2_wksp(HUF_DTable* DTable,
                        const void* src, size_t srcSize,
                              void* workSpace, size_t wkspSize)
@@ -560,48 +635,33 @@ size_t HUF_readDTableX2_wksp(HUF_DTable* DTable,
     HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr;
     U32 *rankStart;
 
-    rankValCol_t* rankVal;
-    U32* rankStats;
-    U32* rankStart0;
-    sortedSymbol_t* sortedSymbol;
-    BYTE* weightList;
-    size_t spaceUsed32 = 0;
-
-    rankVal = (rankValCol_t *)((U32 *)workSpace + spaceUsed32);
-    spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2;
-    rankStats = (U32 *)workSpace + spaceUsed32;
-    spaceUsed32 += HUF_TABLELOG_MAX + 1;
-    rankStart0 = (U32 *)workSpace + spaceUsed32;
-    spaceUsed32 += HUF_TABLELOG_MAX + 2;
-    sortedSymbol = (sortedSymbol_t *)workSpace + (spaceUsed32 * sizeof(U32)) / sizeof(sortedSymbol_t);
-    spaceUsed32 += HUF_ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2;
-    weightList = (BYTE *)((U32 *)workSpace + spaceUsed32);
-    spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
-
-    if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge);
-
-    rankStart = rankStart0 + 1;
-    memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
+    HUF_ReadDTableX2_Workspace* const wksp = (HUF_ReadDTableX2_Workspace*)workSpace;
+
+    if (sizeof(*wksp) > wkspSize) return ERROR(GENERIC);
+
+    rankStart = wksp->rankStart0 + 1;
+    ZSTD_memset(wksp->rankStats, 0, sizeof(wksp->rankStats));
+    ZSTD_memset(wksp->rankStart0, 0, sizeof(wksp->rankStart0));
 
     DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable));   /* if compiler fails here, assertion is wrong */
     if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
-    /* memset(weightList, 0, sizeof(weightList)); */  /* is not necessary, even though some analyzer complain ... */
+    /* ZSTD_memset(weightList, 0, sizeof(weightList)); */  /* is not necessary, even though some analyzer complain ... */
 
-    iSize = HUF_readStats(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize);
+    iSize = HUF_readStats_wksp(wksp->weightList, HUF_SYMBOLVALUE_MAX + 1, wksp->rankStats, &nbSymbols, &tableLog, src, srcSize, wksp->calleeWksp, sizeof(wksp->calleeWksp), /* bmi2 */ 0);
     if (HUF_isError(iSize)) return iSize;
 
     /* check result */
     if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge);   /* DTable can't fit code depth */
 
     /* find maxWeight */
-    for (maxW = tableLog; rankStats[maxW]==0; maxW--) {}  /* necessarily finds a solution before 0 */
+    for (maxW = tableLog; wksp->rankStats[maxW]==0; maxW--) {}  /* necessarily finds a solution before 0 */
 
     /* Get start index of each weight */
     {   U32 w, nextRankStart = 0;
         for (w=1; w<maxW+1; w++) {
-            U32 current = nextRankStart;
-            nextRankStart += rankStats[w];
-            rankStart[w] = current;
+            U32 curr = nextRankStart;
+            nextRankStart += wksp->rankStats[w];
+            rankStart[w] = curr;
         }
         rankStart[0] = nextRankStart;   /* put all 0w symbols at the end of sorted list*/
         sizeOfSort = nextRankStart;
@@ -610,57 +670,51 @@ size_t HUF_readDTableX2_wksp(HUF_DTable* DTable,
     /* sort symbols by weight */
     {   U32 s;
         for (s=0; s<nbSymbols; s++) {
-            U32 const w = weightList[s];
+            U32 const w = wksp->weightList[s];
             U32 const r = rankStart[w]++;
-            sortedSymbol[r].symbol = (BYTE)s;
-            sortedSymbol[r].weight = (BYTE)w;
+            wksp->sortedSymbol[r].symbol = (BYTE)s;
+            wksp->sortedSymbol[r].weight = (BYTE)w;
         }
         rankStart[0] = 0;   /* forget 0w symbols; this is beginning of weight(1) */
     }
 
     /* Build rankVal */
-    {   U32* const rankVal0 = rankVal[0];
+    {   U32* const rankVal0 = wksp->rankVal[0];
         {   int const rescale = (maxTableLog-tableLog) - 1;   /* tableLog <= maxTableLog */
             U32 nextRankVal = 0;
             U32 w;
             for (w=1; w<maxW+1; w++) {
-                U32 current = nextRankVal;
-                nextRankVal += rankStats[w] << (w+rescale);
-                rankVal0[w] = current;
+                U32 curr = nextRankVal;
+                nextRankVal += wksp->rankStats[w] << (w+rescale);
+                rankVal0[w] = curr;
         }   }
         {   U32 const minBits = tableLog+1 - maxW;
             U32 consumed;
             for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) {
-                U32* const rankValPtr = rankVal[consumed];
+                U32* const rankValPtr = wksp->rankVal[consumed];
                 U32 w;
                 for (w = 1; w < maxW+1; w++) {
                     rankValPtr[w] = rankVal0[w] >> consumed;
     }   }   }   }
 
     HUF_fillDTableX2(dt, maxTableLog,
-                   sortedSymbol, sizeOfSort,
-                   rankStart0, rankVal, maxW,
-                   tableLog+1);
+                   wksp->sortedSymbol, sizeOfSort,
+                   wksp->rankStart0, wksp->rankVal, maxW,
+                   tableLog+1,
+                   wksp->calleeWksp, sizeof(wksp->calleeWksp) / sizeof(U32));
 
     dtd.tableLog = (BYTE)maxTableLog;
     dtd.tableType = 1;
-    memcpy(DTable, &dtd, sizeof(dtd));
+    ZSTD_memcpy(DTable, &dtd, sizeof(dtd));
     return iSize;
 }
 
-size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize)
-{
-  U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
-  return HUF_readDTableX2_wksp(DTable, src, srcSize,
-                               workSpace, sizeof(workSpace));
-}
-
 
 FORCE_INLINE_TEMPLATE U32
 HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog)
 {
     size_t const val = BIT_lookBitsFast(DStream, dtLog);   /* note : dtLog >= 1 */
-    memcpy(op, dt+val, 2);
+    ZSTD_memcpy(op, dt+val, 2);
     BIT_skipBits(DStream, dt[val].nbBits);
     return dt[val].length;
 }
@@ -669,7 +723,7 @@ FORCE_INLINE_TEMPLATE U32
 HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog)
 {
     size_t const val = BIT_lookBitsFast(DStream, dtLog);   /* note : dtLog >= 1 */
-    memcpy(op, dt+val, 1);
+    ZSTD_memcpy(op, dt+val, 1);
     if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits);
     else {
         if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) {
@@ -890,20 +944,6 @@ size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize,
 }
 
 
-size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
-                              const void* cSrc, size_t cSrcSize)
-{
-    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
-    return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
-                                       workSpace, sizeof(workSpace));
-}
-
-size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
-    HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
-    return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
-}
-
 size_t HUF_decompress4X2_usingDTable(
           void* dst,  size_t dstSize,
     const void* cSrc, size_t cSrcSize,
@@ -937,20 +977,6 @@ size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
 }
 
 
-size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
-                              const void* cSrc, size_t cSrcSize)
-{
-    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
-    return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
-                                       workSpace, sizeof(workSpace));
-}
-
-size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
-    HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
-    return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
-}
-
 #endif /* HUF_FORCE_DECOMPRESS_X1 */
 
 
@@ -1051,67 +1077,6 @@ U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize)
 }
 
 
-typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
-
-size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
-#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2)
-    static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 };
-#endif
-
-    /* validation checks */
-    if (dstSize == 0) return ERROR(dstSize_tooSmall);
-    if (cSrcSize > dstSize) return ERROR(corruption_detected);   /* invalid */
-    if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
-    if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
-
-    {   U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
-#if defined(HUF_FORCE_DECOMPRESS_X1)
-        (void)algoNb;
-        assert(algoNb == 0);
-        return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize);
-#elif defined(HUF_FORCE_DECOMPRESS_X2)
-        (void)algoNb;
-        assert(algoNb == 1);
-        return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize);
-#else
-        return decompress[algoNb](dst, dstSize, cSrc, cSrcSize);
-#endif
-    }
-}
-
-size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
-    /* validation checks */
-    if (dstSize == 0) return ERROR(dstSize_tooSmall);
-    if (cSrcSize > dstSize) return ERROR(corruption_detected);   /* invalid */
-    if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
-    if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
-
-    {   U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
-#if defined(HUF_FORCE_DECOMPRESS_X1)
-        (void)algoNb;
-        assert(algoNb == 0);
-        return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize);
-#elif defined(HUF_FORCE_DECOMPRESS_X2)
-        (void)algoNb;
-        assert(algoNb == 1);
-        return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize);
-#else
-        return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
-                        HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
-#endif
-    }
-}
-
-size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
-{
-    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
-    return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
-                                         workSpace, sizeof(workSpace));
-}
-
-
 size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst,
                                      size_t dstSize, const void* cSrc,
                                      size_t cSrcSize, void* workSpace,
@@ -1145,8 +1110,8 @@ size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
     /* validation checks */
     if (dstSize == 0) return ERROR(dstSize_tooSmall);
     if (cSrcSize > dstSize) return ERROR(corruption_detected);   /* invalid */
-    if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
-    if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
+    if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
+    if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
 
     {   U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
 #if defined(HUF_FORCE_DECOMPRESS_X1)
@@ -1168,14 +1133,6 @@ size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize,
     }
 }
 
-size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
-                             const void* cSrc, size_t cSrcSize)
-{
-    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
-    return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
-                                      workSpace, sizeof(workSpace));
-}
-
 
 size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2)
 {
@@ -1199,7 +1156,7 @@ size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstS
 {
     const BYTE* ip = (const BYTE*) cSrc;
 
-    size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize);
+    size_t const hSize = HUF_readDTableX1_wksp_bmi2(dctx, cSrc, cSrcSize, workSpace, wkspSize, bmi2);
     if (HUF_isError(hSize)) return hSize;
     if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
     ip += hSize; cSrcSize -= hSize;
@@ -1246,3 +1203,149 @@ size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t ds
 #endif
     }
 }
+
+#ifndef ZSTD_NO_UNUSED_FUNCTIONS
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_readDTableX1_wksp(DTable, src, srcSize,
+                                 workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
+                              const void* cSrc, size_t cSrcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
+                                       workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
+    return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize);
+}
+#endif
+
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize)
+{
+  U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+  return HUF_readDTableX2_wksp(DTable, src, srcSize,
+                               workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize,
+                              const void* cSrc, size_t cSrcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize,
+                                       workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
+    return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
+}
+#endif
+
+#ifndef HUF_FORCE_DECOMPRESS_X2
+size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+                                       workSpace, sizeof(workSpace));
+}
+size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX);
+    return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
+}
+#endif
+
+#ifndef HUF_FORCE_DECOMPRESS_X1
+size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
+                              const void* cSrc, size_t cSrcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+                                       workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);
+    return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);
+}
+#endif
+
+typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
+
+size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2)
+    static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 };
+#endif
+
+    /* validation checks */
+    if (dstSize == 0) return ERROR(dstSize_tooSmall);
+    if (cSrcSize > dstSize) return ERROR(corruption_detected);   /* invalid */
+    if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
+    if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
+
+    {   U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+        (void)algoNb;
+        assert(algoNb == 0);
+        return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+        (void)algoNb;
+        assert(algoNb == 1);
+        return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize);
+#else
+        return decompress[algoNb](dst, dstSize, cSrc, cSrcSize);
+#endif
+    }
+}
+
+size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    /* validation checks */
+    if (dstSize == 0) return ERROR(dstSize_tooSmall);
+    if (cSrcSize > dstSize) return ERROR(corruption_detected);   /* invalid */
+    if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; }   /* not compressed */
+    if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; }   /* RLE */
+
+    {   U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+#if defined(HUF_FORCE_DECOMPRESS_X1)
+        (void)algoNb;
+        assert(algoNb == 0);
+        return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize);
+#elif defined(HUF_FORCE_DECOMPRESS_X2)
+        (void)algoNb;
+        assert(algoNb == 1);
+        return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize);
+#else
+        return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
+                        HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
+#endif
+    }
+}
+
+size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+                                         workSpace, sizeof(workSpace));
+}
+
+size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize,
+                             const void* cSrc, size_t cSrcSize)
+{
+    U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
+    return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize,
+                                      workSpace, sizeof(workSpace));
+}
+#endif
index c8cb8ec..ce33547 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -14,7 +14,7 @@
 /*-*******************************************************
 *  Dependencies
 *********************************************************/
-#include <string.h>      /* memcpy, memmove, memset */
+#include "../common/zstd_deps.h"   /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
 #include "../common/cpu.h"         /* bmi2 */
 #include "../common/mem.h"         /* low level memory routines */
 #define FSE_STATIC_LINKING_ONLY
@@ -127,11 +127,11 @@ static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict,
         ddict->dictContent = dict;
         if (!dict) dictSize = 0;
     } else {
-        void* const internalBuffer = ZSTD_malloc(dictSize, ddict->cMem);
+        void* const internalBuffer = ZSTD_customMalloc(dictSize, ddict->cMem);
         ddict->dictBuffer = internalBuffer;
         ddict->dictContent = internalBuffer;
         if (!internalBuffer) return ERROR(memory_allocation);
-        memcpy(internalBuffer, dict, dictSize);
+        ZSTD_memcpy(internalBuffer, dict, dictSize);
     }
     ddict->dictSize = dictSize;
     ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001);  /* cover both little and big endian */
@@ -147,9 +147,9 @@ ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
                                       ZSTD_dictContentType_e dictContentType,
                                       ZSTD_customMem customMem)
 {
-    if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+    if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
 
-    {   ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem);
+    {   ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_customMalloc(sizeof(ZSTD_DDict), customMem);
         if (ddict == NULL) return NULL;
         ddict->cMem = customMem;
         {   size_t const initResult = ZSTD_initDDict_internal(ddict,
@@ -198,7 +198,7 @@ const ZSTD_DDict* ZSTD_initStaticDDict(
     if ((size_t)sBuffer & 7) return NULL;   /* 8-aligned */
     if (sBufferSize < neededSpace) return NULL;
     if (dictLoadMethod == ZSTD_dlm_byCopy) {
-        memcpy(ddict+1, dict, dictSize);  /* local copy */
+        ZSTD_memcpy(ddict+1, dict, dictSize);  /* local copy */
         dict = ddict+1;
     }
     if (ZSTD_isError( ZSTD_initDDict_internal(ddict,
@@ -213,8 +213,8 @@ size_t ZSTD_freeDDict(ZSTD_DDict* ddict)
 {
     if (ddict==NULL) return 0;   /* support free on NULL */
     {   ZSTD_customMem const cMem = ddict->cMem;
-        ZSTD_free(ddict->dictBuffer, cMem);
-        ZSTD_free(ddict, cMem);
+        ZSTD_customFree(ddict->dictBuffer, cMem);
+        ZSTD_customFree(ddict, cMem);
         return 0;
     }
 }
index af307ef..bd03268 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -15,7 +15,7 @@
 /*-*******************************************************
  *  Dependencies
  *********************************************************/
-#include <stddef.h>   /* size_t */
+#include "../common/zstd_deps.h"   /* size_t */
 #include "../zstd.h"     /* ZSTD_DDict, and several public functions */
 
 
index be5c7cf..910bc03 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
 /*-*******************************************************
 *  Dependencies
 *********************************************************/
-#include <string.h>      /* memcpy, memmove, memset */
+#include "../common/zstd_deps.h"   /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
 #include "../common/cpu.h"         /* bmi2 */
 #include "../common/mem.h"         /* low level memory routines */
 #define FSE_STATIC_LINKING_ONLY
 #include "../common/fse.h"
 #define HUF_STATIC_LINKING_ONLY
 #include "../common/huf.h"
+#include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */
 #include "../common/zstd_internal.h"  /* blockProperties_t */
 #include "zstd_decompress_internal.h"   /* ZSTD_DCtx */
 #include "zstd_ddict.h"  /* ZSTD_DDictDictContent */
 #endif
 
 
+
+/*************************************
+ * Multiple DDicts Hashset internals *
+ *************************************/
+
+#define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 4
+#define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3   /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float.
+                                                     * Currently, that means a 0.75 load factor.
+                                                     * So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded
+                                                     * the load factor of the ddict hash set.
+                                                     */
+
+#define DDICT_HASHSET_TABLE_BASE_SIZE 64
+#define DDICT_HASHSET_RESIZE_FACTOR 2
+
+/* Hash function to determine starting position of dict insertion within the table
+ * Returns an index between [0, hashSet->ddictPtrTableSize]
+ */
+static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) {
+    const U64 hash = XXH64(&dictID, sizeof(U32), 0);
+    /* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */
+    return hash & (hashSet->ddictPtrTableSize - 1);
+}
+
+/* Adds DDict to a hashset without resizing it.
+ * If inserting a DDict with a dictID that already exists in the set, replaces the one in the set.
+ * Returns 0 if successful, or a zstd error code if something went wrong.
+ */
+static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) {
+    const U32 dictID = ZSTD_getDictID_fromDDict(ddict);
+    size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);
+    const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;
+    RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!");
+    DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);
+    while (hashSet->ddictPtrTable[idx] != NULL) {
+        /* Replace existing ddict if inserting ddict with same dictID */
+        if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) {
+            DEBUGLOG(4, "DictID already exists, replacing rather than adding");
+            hashSet->ddictPtrTable[idx] = ddict;
+            return 0;
+        }
+        idx &= idxRangeMask;
+        idx++;
+    }
+    DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);
+    hashSet->ddictPtrTable[idx] = ddict;
+    hashSet->ddictPtrCount++;
+    return 0;
+}
+
+/* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and
+ * rehashes all values, allocates new table, frees old table.
+ * Returns 0 on success, otherwise a zstd error code.
+ */
+static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {
+    size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR;
+    const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem);
+    const ZSTD_DDict** oldTable = hashSet->ddictPtrTable;
+    size_t oldTableSize = hashSet->ddictPtrTableSize;
+    size_t i;
+
+    DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize);
+    RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!");
+    hashSet->ddictPtrTable = newTable;
+    hashSet->ddictPtrTableSize = newTableSize;
+    hashSet->ddictPtrCount = 0;
+    for (i = 0; i < oldTableSize; ++i) {
+        if (oldTable[i] != NULL) {
+            FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), "");
+        }
+    }
+    ZSTD_customFree((void*)oldTable, customMem);
+    DEBUGLOG(4, "Finished re-hash");
+    return 0;
+}
+
+/* Fetches a DDict with the given dictID
+ * Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL.
+ */
+static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) {
+    size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);
+    const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;
+    DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);
+    for (;;) {
+        size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]);
+        if (currDictID == dictID || currDictID == 0) {
+            /* currDictID == 0 implies a NULL ddict entry */
+            break;
+        } else {
+            idx &= idxRangeMask;    /* Goes to start of table when we reach the end */
+            idx++;
+        }
+    }
+    DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);
+    return hashSet->ddictPtrTable[idx];
+}
+
+/* Allocates space for and returns a ddict hash set
+ * The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with.
+ * Returns NULL if allocation failed.
+ */
+static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) {
+    ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem);
+    DEBUGLOG(4, "Allocating new hash set");
+    ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem);
+    ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE;
+    ret->ddictPtrCount = 0;
+    if (!ret || !ret->ddictPtrTable) {
+        return NULL;
+    }
+    return ret;
+}
+
+/* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself.
+ * Note: The ZSTD_DDict* within the table are NOT freed.
+ */
+static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {
+    DEBUGLOG(4, "Freeing ddict hash set");
+    if (hashSet && hashSet->ddictPtrTable) {
+        ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem);
+    }
+    if (hashSet) {
+        ZSTD_customFree(hashSet, customMem);
+    }
+}
+
+/* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set.
+ * Returns 0 on success, or a ZSTD error.
+ */
+static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) {
+    DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize);
+    if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) {
+        FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), "");
+    }
+    FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), "");
+    return 0;
+}
+
 /*-*************************************************************
 *   Context management
 ***************************************************************/
@@ -94,11 +233,19 @@ static size_t ZSTD_startingInputLength(ZSTD_format_e format)
     return startingInputLength;
 }
 
+static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx)
+{
+    assert(dctx->streamStage == zdss_init);
+    dctx->format = ZSTD_f_zstd1;
+    dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
+    dctx->outBufferMode = ZSTD_bm_buffered;
+    dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum;
+    dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict;
+}
+
 static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
 {
-    dctx->format = ZSTD_f_zstd1;  /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */
     dctx->staticSize  = 0;
-    dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
     dctx->ddict       = NULL;
     dctx->ddictLocal  = NULL;
     dctx->dictEnd     = NULL;
@@ -113,7 +260,8 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
     dctx->noForwardProgress = 0;
     dctx->oversizedDuration = 0;
     dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
-    dctx->outBufferMode = ZSTD_obm_buffered;
+    dctx->ddictSet = NULL;
+    ZSTD_DCtx_resetParameters(dctx);
 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
     dctx->dictContentEndForFuzzing = NULL;
 #endif
@@ -134,9 +282,9 @@ ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
 
 ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
 {
-    if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
+    if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
 
-    {   ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem);
+    {   ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem);
         if (!dctx) return NULL;
         dctx->customMem = customMem;
         ZSTD_initDCtx_internal(dctx);
@@ -164,13 +312,17 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
     RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx");
     {   ZSTD_customMem const cMem = dctx->customMem;
         ZSTD_clearDict(dctx);
-        ZSTD_free(dctx->inBuff, cMem);
+        ZSTD_customFree(dctx->inBuff, cMem);
         dctx->inBuff = NULL;
 #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
         if (dctx->legacyContext)
             ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);
 #endif
-        ZSTD_free(dctx, cMem);
+        if (dctx->ddictSet) {
+            ZSTD_freeDDictHashSet(dctx->ddictSet, cMem);
+            dctx->ddictSet = NULL;
+        }
+        ZSTD_customFree(dctx, cMem);
         return 0;
     }
 }
@@ -179,7 +331,30 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
 void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
 {
     size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx);
-    memcpy(dstDCtx, srcDCtx, toCopy);  /* no need to copy workspace */
+    ZSTD_memcpy(dstDCtx, srcDCtx, toCopy);  /* no need to copy workspace */
+}
+
+/* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on
+ * the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then
+ * accordingly sets the ddict to be used to decompress the frame.
+ *
+ * If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is.
+ *
+ * ZSTD_d_refMultipleDDicts must be enabled for this function to be called.
+ */
+static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) {
+    assert(dctx->refMultipleDDicts && dctx->ddictSet);
+    DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame");
+    if (dctx->ddict) {
+        const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID);
+        if (frameDDict) {
+            DEBUGLOG(4, "DDict found!");
+            ZSTD_clearDict(dctx);
+            dctx->dictID = dctx->fParams.dictID;
+            dctx->ddict = frameDDict;
+            dctx->dictUses = ZSTD_use_indefinitely;
+        }
+    }
 }
 
 
@@ -246,7 +421,7 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s
     const BYTE* ip = (const BYTE*)src;
     size_t const minInputSize = ZSTD_startingInputLength(format);
 
-    memset(zfhPtr, 0, sizeof(*zfhPtr));   /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */
+    ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr));   /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */
     if (srcSize < minInputSize) return minInputSize;
     RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter");
 
@@ -256,7 +431,7 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s
             /* skippable frame */
             if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
                 return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */
-            memset(zfhPtr, 0, sizeof(*zfhPtr));
+            ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr));
             zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);
             zfhPtr->frameType = ZSTD_skippableFrame;
             return 0;
@@ -433,12 +608,19 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
 
 /** ZSTD_decodeFrameHeader() :
  * `headerSize` must be the size provided by ZSTD_frameHeaderSize().
+ * If multiple DDict references are enabled, also will choose the correct DDict to use.
  * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
 static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
 {
     size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);
     if (ZSTD_isError(result)) return result;    /* invalid header */
     RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small");
+
+    /* Reference DDict requested by frame if dctx references multiple ddicts */
+    if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) {
+        ZSTD_DCtx_selectFrameDDict(dctx);
+    }
+
 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
     /* Skip the dictID check in fuzzing mode, because it makes the search
      * harder.
@@ -446,7 +628,9 @@ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t he
     RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID),
                     dictionary_wrong, "");
 #endif
-    if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
+    dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0;
+    if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0);
+    dctx->processedCSize += headerSize;
     return 0;
 }
 
@@ -461,7 +645,7 @@ static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret)
 static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize)
 {
     ZSTD_frameSizeInfo frameSizeInfo;
-    memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));
+    ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));
 
 #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
     if (ZSTD_isLegacy(src, srcSize))
@@ -516,7 +700,7 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize
             ip += 4;
         }
 
-        frameSizeInfo.compressedSize = ip - ipstart;
+        frameSizeInfo.compressedSize = (size_t)(ip - ipstart);
         frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN)
                                         ? zfh.frameContentSize
                                         : nbBlocks * zfh.blockSizeMax;
@@ -569,7 +753,7 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
 size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
 {
     DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize);
-    ZSTD_checkContinuity(dctx, blockStart);
+    ZSTD_checkContinuity(dctx, blockStart, blockSize);
     dctx->previousDstEnd = (const char*)blockStart + blockSize;
     return blockSize;
 }
@@ -579,12 +763,12 @@ static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity,
                           const void* src, size_t srcSize)
 {
     DEBUGLOG(5, "ZSTD_copyRawBlock");
+    RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, "");
     if (dst == NULL) {
         if (srcSize == 0) return 0;
         RETURN_ERROR(dstBuffer_null, "");
     }
-    RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, "");
-    memcpy(dst, src, srcSize);
+    ZSTD_memcpy(dst, src, srcSize);
     return srcSize;
 }
 
@@ -592,15 +776,41 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
                                BYTE b,
                                size_t regenSize)
 {
+    RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, "");
     if (dst == NULL) {
         if (regenSize == 0) return 0;
         RETURN_ERROR(dstBuffer_null, "");
     }
-    RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, "");
-    memset(dst, b, regenSize);
+    ZSTD_memset(dst, b, regenSize);
     return regenSize;
 }
 
+static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming)
+{
+#if ZSTD_TRACE
+    if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) {
+        ZSTD_Trace trace;
+        ZSTD_memset(&trace, 0, sizeof(trace));
+        trace.version = ZSTD_VERSION_NUMBER;
+        trace.streaming = streaming;
+        if (dctx->ddict) {
+            trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict);
+            trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict);
+            trace.dictionaryIsCold = dctx->ddictIsCold;
+        }
+        trace.uncompressedSize = (size_t)uncompressedSize;
+        trace.compressedSize = (size_t)compressedSize;
+        trace.dctx = dctx;
+        ZSTD_trace_decompress_end(dctx->traceCtx, &trace);
+    }
+#else
+    (void)dctx;
+    (void)uncompressedSize;
+    (void)compressedSize;
+    (void)streaming;
+#endif
+}
+
 
 /*! ZSTD_decompressFrame() :
  * @dctx must be properly initialized
@@ -610,8 +820,9 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
                                    void* dst, size_t dstCapacity,
                              const void** srcPtr, size_t *srcSizePtr)
 {
-    const BYTE* ip = (const BYTE*)(*srcPtr);
-    BYTE* const ostart = (BYTE* const)dst;
+    const BYTE* const istart = (const BYTE*)(*srcPtr);
+    const BYTE* ip = istart;
+    BYTE* const ostart = (BYTE*)dst;
     BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart;
     BYTE* op = ostart;
     size_t remainingSrcSize = *srcSizePtr;
@@ -647,13 +858,13 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
         switch(blockProperties.blockType)
         {
         case bt_compressed:
-            decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1);
+            decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oend-op), ip, cBlockSize, /* frame */ 1);
             break;
         case bt_raw :
-            decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize);
+            decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize);
             break;
         case bt_rle :
-            decodedSize = ZSTD_setRleBlock(op, oend-op, *ip, blockProperties.origSize);
+            decodedSize = ZSTD_setRleBlock(op, (size_t)(oend-op), *ip, blockProperties.origSize);
             break;
         case bt_reserved :
         default:
@@ -661,7 +872,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
         }
 
         if (ZSTD_isError(decodedSize)) return decodedSize;
-        if (dctx->fParams.checksumFlag)
+        if (dctx->validateChecksum)
             XXH64_update(&dctx->xxhState, op, decodedSize);
         if (decodedSize != 0)
             op += decodedSize;
@@ -676,19 +887,21 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
                         corruption_detected, "");
     }
     if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
-        U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);
-        U32 checkRead;
         RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, "");
-        checkRead = MEM_readLE32(ip);
-        RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, "");
+        if (!dctx->forceIgnoreChecksum) {
+            U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);
+            U32 checkRead;
+            checkRead = MEM_readLE32(ip);
+            RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, "");
+        }
         ip += 4;
         remainingSrcSize -= 4;
     }
-
+    ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0);
     /* Allow caller to get size read */
     *srcPtr = ip;
     *srcSizePtr = remainingSrcSize;
-    return op-ostart;
+    return (size_t)(op-ostart);
 }
 
 static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
@@ -721,7 +934,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
             decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);
             if (ZSTD_isError(decodedSize)) return decodedSize;
 
-            assert(decodedSize <=- dstCapacity);
+            assert(decodedSize <= dstCapacity);
             dst = (BYTE*)dst + decodedSize;
             dstCapacity -= decodedSize;
 
@@ -753,7 +966,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
              * use this in all cases but ddict */
             FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), "");
         }
-        ZSTD_checkContinuity(dctx, dst);
+        ZSTD_checkContinuity(dctx, dst, dstCapacity);
 
         {   const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,
                                                     &src, &srcSize);
@@ -761,15 +974,13 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
                 (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown)
              && (moreThan1Frame==1),
                 srcSize_wrong,
-                "at least one frame successfully completed, but following "
-                "bytes are garbage: it's more likely to be a srcSize error, "
-                "specifying more bytes than compressed size of frame(s). This "
-                "error message replaces ERROR(prefix_unknown), which would be "
-                "confusing, as the first header is actually correct. Note that "
-                "one could be unlucky, it might be a corruption error instead, "
-                "happening right at the place where we expect zstd magic "
-                "bytes. But this is _much_ less likely than a srcSize field "
-                "error.");
+                "At least one frame successfully completed, "
+                "but following bytes are garbage: "
+                "it's more likely to be a srcSize error, "
+                "specifying more input bytes than size of frame(s). "
+                "Note: one could be unlucky, it might be a corruption error instead, "
+                "happening right at the place where we expect zstd magic bytes. "
+                "But this is _much_ less likely than a srcSize field error.");
             if (ZSTD_isError(res)) return res;
             assert(res <= dstCapacity);
             if (res != 0)
@@ -781,7 +992,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
 
     RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed");
 
-    return (BYTE*)dst - (BYTE*)dststart;
+    return (size_t)((BYTE*)dst - (BYTE*)dststart);
 }
 
 size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,
@@ -890,7 +1101,9 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
     DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);
     /* Sanity check */
     RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed");
-    if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
+    ZSTD_checkContinuity(dctx, dst, dstCapacity);
+
+    dctx->processedCSize += srcSize;
 
     switch (dctx->stage)
     {
@@ -899,21 +1112,21 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
         if (dctx->format == ZSTD_f_zstd1) {  /* allows header */
             assert(srcSize >= ZSTD_FRAMEIDSIZE);  /* to read skippable magic number */
             if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {        /* skippable frame */
-                memcpy(dctx->headerBuffer, src, srcSize);
+                ZSTD_memcpy(dctx->headerBuffer, src, srcSize);
                 dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize;  /* remaining to load to get full skippable frame header */
                 dctx->stage = ZSTDds_decodeSkippableHeader;
                 return 0;
         }   }
         dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);
         if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
-        memcpy(dctx->headerBuffer, src, srcSize);
+        ZSTD_memcpy(dctx->headerBuffer, src, srcSize);
         dctx->expected = dctx->headerSize - srcSize;
         dctx->stage = ZSTDds_decodeFrameHeader;
         return 0;
 
     case ZSTDds_decodeFrameHeader:
         assert(src != NULL);
-        memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
+        ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
         FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), "");
         dctx->expected = ZSTD_blockHeaderSize;
         dctx->stage = ZSTDds_decodeBlockHeader;
@@ -977,7 +1190,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
             RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum");
             DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);
             dctx->decodedSize += rSize;
-            if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
+            if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize);
             dctx->previousDstEnd = (char*)dst + rSize;
 
             /* Stay on the same stage until we are finished streaming the block. */
@@ -995,6 +1208,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
                     dctx->expected = 4;
                     dctx->stage = ZSTDds_checkChecksum;
                 } else {
+                    ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);
                     dctx->expected = 0;   /* ends here */
                     dctx->stage = ZSTDds_getFrameHeaderSize;
                 }
@@ -1007,10 +1221,14 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
 
     case ZSTDds_checkChecksum:
         assert(srcSize == 4);  /* guaranteed by dctx->expected */
-        {   U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
-            U32 const check32 = MEM_readLE32(src);
-            DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);
-            RETURN_ERROR_IF(check32 != h32, checksum_wrong, "");
+        {
+            if (dctx->validateChecksum) {
+                U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
+                U32 const check32 = MEM_readLE32(src);
+                DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);
+                RETURN_ERROR_IF(check32 != h32, checksum_wrong, "");
+            }
+            ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);
             dctx->expected = 0;
             dctx->stage = ZSTDds_getFrameHeaderSize;
             return 0;
@@ -1019,7 +1237,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
     case ZSTDds_decodeSkippableHeader:
         assert(src != NULL);
         assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);
-        memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize);   /* complete skippable header */
+        ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize);   /* complete skippable header */
         dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE);   /* note : dctx->expected can grow seriously large, beyond local buffer size */
         dctx->stage = ZSTDds_skipFrame;
         return 0;
@@ -1075,7 +1293,7 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
                                                 workspace, workspaceSize);
 #else
         size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,
-                                                dictPtr, dictEnd - dictPtr,
+                                                dictPtr, (size_t)(dictEnd - dictPtr),
                                                 workspace, workspaceSize);
 #endif
         RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, "");
@@ -1084,40 +1302,46 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
 
     {   short offcodeNCount[MaxOff+1];
         unsigned offcodeMaxValue = MaxOff, offcodeLog;
-        size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
+        size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr));
         RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
         RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, "");
         RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
         ZSTD_buildFSETable( entropy->OFTable,
                             offcodeNCount, offcodeMaxValue,
                             OF_base, OF_bits,
-                            offcodeLog);
+                            offcodeLog,
+                            entropy->workspace, sizeof(entropy->workspace),
+                            /* bmi2 */0);
         dictPtr += offcodeHeaderSize;
     }
 
     {   short matchlengthNCount[MaxML+1];
         unsigned matchlengthMaxValue = MaxML, matchlengthLog;
-        size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
+        size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr));
         RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
         RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, "");
         RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");
         ZSTD_buildFSETable( entropy->MLTable,
                             matchlengthNCount, matchlengthMaxValue,
                             ML_base, ML_bits,
-                            matchlengthLog);
+                            matchlengthLog,
+                            entropy->workspace, sizeof(entropy->workspace),
+                            /* bmi2 */ 0);
         dictPtr += matchlengthHeaderSize;
     }
 
     {   short litlengthNCount[MaxLL+1];
         unsigned litlengthMaxValue = MaxLL, litlengthLog;
-        size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
+        size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr));
         RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
         RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, "");
         RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");
         ZSTD_buildFSETable( entropy->LLTable,
                             litlengthNCount, litlengthMaxValue,
                             LL_base, LL_bits,
-                            litlengthLog);
+                            litlengthLog,
+                            entropy->workspace, sizeof(entropy->workspace),
+                            /* bmi2 */ 0);
         dictPtr += litlengthHeaderSize;
     }
 
@@ -1131,7 +1355,7 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
             entropy->rep[i] = rep;
     }   }
 
-    return dictPtr - (const BYTE*)dict;
+    return (size_t)(dictPtr - (const BYTE*)dict);
 }
 
 static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
@@ -1158,8 +1382,12 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict
 size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
 {
     assert(dctx != NULL);
+#if ZSTD_TRACE
+    dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0;
+#endif
     dctx->expected = ZSTD_startingInputLength(dctx->format);  /* dctx->format must be properly set */
     dctx->stage = ZSTDds_getFrameHeaderSize;
+    dctx->processedCSize = 0;
     dctx->decodedSize = 0;
     dctx->previousDstEnd = NULL;
     dctx->prefixStart = NULL;
@@ -1170,7 +1398,7 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
     dctx->dictID = 0;
     dctx->bType = bt_reserved;
     ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
-    memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue));  /* initial repcodes */
+    ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue));  /* initial repcodes */
     dctx->LLTptr = dctx->entropy.LLTable;
     dctx->MLTptr = dctx->entropy.MLTable;
     dctx->OFTptr = dctx->entropy.OFTable;
@@ -1373,6 +1601,16 @@ size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
     if (ddict) {
         dctx->ddict = ddict;
         dctx->dictUses = ZSTD_use_indefinitely;
+        if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) {
+            if (dctx->ddictSet == NULL) {
+                dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem);
+                if (!dctx->ddictSet) {
+                    RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!");
+                }
+            }
+            assert(!dctx->staticSize);  /* Impossible: ddictSet cannot have been allocated if static dctx */
+            FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), "");
+        }
     }
     return 0;
 }
@@ -1394,7 +1632,7 @@ size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
 
 size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
 {
-    return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format);
+    return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format);
 }
 
 ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
@@ -1411,8 +1649,16 @@ ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
             ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
             return bounds;
         case ZSTD_d_stableOutBuffer:
-            bounds.lowerBound = (int)ZSTD_obm_buffered;
-            bounds.upperBound = (int)ZSTD_obm_stable;
+            bounds.lowerBound = (int)ZSTD_bm_buffered;
+            bounds.upperBound = (int)ZSTD_bm_stable;
+            return bounds;
+        case ZSTD_d_forceIgnoreChecksum:
+            bounds.lowerBound = (int)ZSTD_d_validateChecksum;
+            bounds.upperBound = (int)ZSTD_d_ignoreChecksum;
+            return bounds;
+        case ZSTD_d_refMultipleDDicts:
+            bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict;
+            bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts;
             return bounds;
         default:;
     }
@@ -1436,6 +1682,29 @@ static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value)
     RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \
 }
 
+size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value)
+{
+    switch (param) {
+        case ZSTD_d_windowLogMax:
+            *value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize);
+            return 0;
+        case ZSTD_d_format:
+            *value = (int)dctx->format;
+            return 0;
+        case ZSTD_d_stableOutBuffer:
+            *value = (int)dctx->outBufferMode;
+            return 0;
+        case ZSTD_d_forceIgnoreChecksum:
+            *value = (int)dctx->forceIgnoreChecksum;
+            return 0;
+        case ZSTD_d_refMultipleDDicts:
+            *value = (int)dctx->refMultipleDDicts;
+            return 0;
+        default:;
+    }
+    RETURN_ERROR(parameter_unsupported, "");
+}
+
 size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value)
 {
     RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
@@ -1451,7 +1720,18 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value
             return 0;
         case ZSTD_d_stableOutBuffer:
             CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value);
-            dctx->outBufferMode = (ZSTD_outBufferMode_e)value;
+            dctx->outBufferMode = (ZSTD_bufferMode_e)value;
+            return 0;
+        case ZSTD_d_forceIgnoreChecksum:
+            CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value);
+            dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value;
+            return 0;
+        case ZSTD_d_refMultipleDDicts:
+            CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value);
+            if (dctx->staticSize != 0) {
+                RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!");
+            }
+            dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value;
             return 0;
         default:;
     }
@@ -1469,8 +1749,7 @@ size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)
       || (reset == ZSTD_reset_session_and_parameters) ) {
         RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
         ZSTD_clearDict(dctx);
-        dctx->format = ZSTD_f_zstd1;
-        dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
+        ZSTD_DCtx_resetParameters(dctx);
     }
     return 0;
 }
@@ -1524,7 +1803,7 @@ static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const ne
 {
     if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize))
         zds->oversizedDuration++;
-    else 
+    else
         zds->oversizedDuration = 0;
 }
 
@@ -1538,7 +1817,7 @@ static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const*
 {
     ZSTD_outBuffer const expect = zds->expectedOutBuffer;
     /* No requirement when ZSTD_obm_stable is not enabled. */
-    if (zds->outBufferMode != ZSTD_obm_stable)
+    if (zds->outBufferMode != ZSTD_bm_stable)
         return 0;
     /* Any buffer is allowed in zdss_init, this must be the same for every other call until
      * the context is reset.
@@ -1548,7 +1827,7 @@ static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const*
     /* The buffer must match our expectation exactly. */
     if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size)
         return 0;
-    RETURN_ERROR(dstBuffer_wrong, "ZSTD_obm_stable enabled but output differs!");
+    RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!");
 }
 
 /* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream()
@@ -1560,7 +1839,7 @@ static size_t ZSTD_decompressContinueStream(
             ZSTD_DStream* zds, char** op, char* oend,
             void const* src, size_t srcSize) {
     int const isSkipFrame = ZSTD_isSkipFrame(zds);
-    if (zds->outBufferMode == ZSTD_obm_buffered) {
+    if (zds->outBufferMode == ZSTD_bm_buffered) {
         size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart;
         size_t const decodedSize = ZSTD_decompressContinue(zds,
                 zds->outBuff + zds->outStart, dstSize, src, srcSize);
@@ -1573,14 +1852,14 @@ static size_t ZSTD_decompressContinueStream(
         }
     } else {
         /* Write directly into the output buffer */
-        size_t const dstSize = isSkipFrame ? 0 : oend - *op;
+        size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op);
         size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize);
         FORWARD_IF_ERROR(decodedSize, "");
         *op += decodedSize;
         /* Flushing is not needed. */
         zds->streamStage = zdss_read;
         assert(*op <= oend);
-        assert(zds->outBufferMode == ZSTD_obm_stable);
+        assert(zds->outBufferMode == ZSTD_bm_stable);
     }
     return 0;
 }
@@ -1635,6 +1914,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
             }   }
 #endif
             {   size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
+                if (zds->refMultipleDDicts && zds->ddictSet) {
+                    ZSTD_DCtx_selectFrameDDict(zds);
+                }
                 DEBUGLOG(5, "header size : %u", (U32)hSize);
                 if (ZSTD_isError(hSize)) {
 #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
@@ -1663,14 +1945,14 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
                     assert(iend >= ip);
                     if (toLoad > remainingInput) {   /* not enough input to load full header */
                         if (remainingInput > 0) {
-                            memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);
+                            ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);
                             zds->lhSize += remainingInput;
                         }
                         input->pos = input->size;
                         return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize;   /* remaining header bytes + next block header */
                     }
                     assert(ip != NULL);
-                    memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;
+                    ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;
                     break;
             }   }
 
@@ -1678,10 +1960,10 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
             if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
                 && zds->fParams.frameType != ZSTD_skippableFrame
                 && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
-                size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart);
+                size_t const cSize = ZSTD_findFrameCompressedSize(istart, (size_t)(iend-istart));
                 if (cSize <= (size_t)(iend-istart)) {
                     /* shortcut : using single-pass mode */
-                    size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, ZSTD_getDDict(zds));
+                    size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds));
                     if (ZSTD_isError(decompressedSize)) return decompressedSize;
                     DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
                     ip = istart + cSize;
@@ -1693,7 +1975,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
             }   }
 
             /* Check output buffer is large enough for ZSTD_odm_stable. */
-            if (zds->outBufferMode == ZSTD_obm_stable
+            if (zds->outBufferMode == ZSTD_bm_stable
                 && zds->fParams.frameType != ZSTD_skippableFrame
                 && zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
                 && (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) {
@@ -1723,7 +2005,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
 
             /* Adapt buffer sizes to frame header instructions */
             {   size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);
-                size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_obm_buffered
+                size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered
                         ? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize)
                         : 0;
 
@@ -1731,7 +2013,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
 
                 {   int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize);
                     int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds);
-                    
+
                     if (tooSmall || tooLarge) {
                         size_t const bufferSize = neededInBuffSize + neededOutBuffSize;
                         DEBUGLOG(4, "inBuff  : from %u to %u",
@@ -1745,10 +2027,10 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
                                 bufferSize > zds->staticSize - sizeof(ZSTD_DCtx),
                                 memory_allocation, "");
                         } else {
-                            ZSTD_free(zds->inBuff, zds->customMem);
+                            ZSTD_customFree(zds->inBuff, zds->customMem);
                             zds->inBuffSize = 0;
                             zds->outBuffSize = 0;
-                            zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem);
+                            zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem);
                             RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, "");
                         }
                         zds->inBuffSize = neededInBuffSize;
@@ -1760,7 +2042,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
 
         case zdss_read:
             DEBUGLOG(5, "stage zdss_read");
-            {   size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip);
+            {   size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip));
                 DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize);
                 if (neededInSize==0) {  /* end of frame */
                     zds->streamStage = zdss_init;
@@ -1790,7 +2072,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
                     RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos,
                                     corruption_detected,
                                     "should never happen");
-                    loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip);
+                    loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip));
                 }
                 ip += loadedSize;
                 zds->inPos += loadedSize;
@@ -1804,7 +2086,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
             }
         case zdss_flush:
             {   size_t const toFlushSize = zds->outEnd - zds->outStart;
-                size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize);
+                size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize);
                 op += flushedSize;
                 zds->outStart += flushedSize;
                 if (flushedSize == toFlushSize) {  /* flush completed */
index ad3b3d8..349dcdc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -14,7 +14,7 @@
 /*-*******************************************************
 *  Dependencies
 *********************************************************/
-#include <string.h>      /* memcpy, memmove, memset */
+#include "../common/zstd_deps.h"   /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
 #include "../common/compiler.h"    /* prefetch */
 #include "../common/cpu.h"         /* bmi2 */
 #include "../common/mem.h"         /* low level memory routines */
@@ -44,7 +44,7 @@
 /*_*******************************************************
 *  Memory operations
 **********************************************************/
-static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); }
+static void ZSTD_copy4(void* dst, const void* src) { ZSTD_memcpy(dst, src, 4); }
 
 
 /*-*************************************************************
@@ -166,7 +166,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
                 dctx->litSize = litSize;
                 dctx->litEntropy = 1;
                 if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable;
-                memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
+                ZSTD_memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
                 return litCSize + lhSize;
             }
 
@@ -191,10 +191,10 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
 
                 if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) {  /* risk reading beyond src buffer with wildcopy */
                     RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected, "");
-                    memcpy(dctx->litBuffer, istart+lhSize, litSize);
+                    ZSTD_memcpy(dctx->litBuffer, istart+lhSize, litSize);
                     dctx->litPtr = dctx->litBuffer;
                     dctx->litSize = litSize;
-                    memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
+                    ZSTD_memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
                     return lhSize+litSize;
                 }
                 /* direct reference into compressed stream */
@@ -223,7 +223,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
                     break;
                 }
                 RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, "");
-                memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);
+                ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);
                 dctx->litPtr = dctx->litBuffer;
                 dctx->litSize = litSize;
                 return lhSize+1;
@@ -236,7 +236,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
 
 /* Default FSE distribution tables.
  * These are pre-calculated FSE decoding tables using default distributions as defined in specification :
- * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#default-distributions
+ * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#default-distributions
  * They were generated programmatically with following method :
  * - start from default distributions, present in /lib/common/zstd_internal.h
  * - generate tables normally, using ZSTD_buildFSETable()
@@ -364,23 +364,26 @@ static void ZSTD_buildSeqTable_rle(ZSTD_seqSymbol* dt, U32 baseValue, U32 nbAddB
  * generate FSE decoding table for one symbol (ll, ml or off)
  * cannot fail if input is valid =>
  * all inputs are presumed validated at this stage */
-void
-ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
+FORCE_INLINE_TEMPLATE
+void ZSTD_buildFSETable_body(ZSTD_seqSymbol* dt,
             const short* normalizedCounter, unsigned maxSymbolValue,
             const U32* baseValue, const U32* nbAdditionalBits,
-            unsigned tableLog)
+            unsigned tableLog, void* wksp, size_t wkspSize)
 {
     ZSTD_seqSymbol* const tableDecode = dt+1;
-    U16 symbolNext[MaxSeq+1];
-
     U32 const maxSV1 = maxSymbolValue + 1;
     U32 const tableSize = 1 << tableLog;
-    U32 highThreshold = tableSize-1;
+
+    U16* symbolNext = (U16*)wksp;
+    BYTE* spread = (BYTE*)(symbolNext + MaxSeq + 1);
+    U32 highThreshold = tableSize - 1;
+
 
     /* Sanity Checks */
     assert(maxSymbolValue <= MaxSeq);
     assert(tableLog <= MaxFSELog);
-
+    assert(wkspSize >= ZSTD_BUILD_FSE_TABLE_WKSP_SIZE);
+    (void)wkspSize;
     /* Init, lay down lowprob symbols */
     {   ZSTD_seqSymbol_header DTableH;
         DTableH.tableLog = tableLog;
@@ -396,16 +399,69 @@ ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
                     assert(normalizedCounter[s]>=0);
                     symbolNext[s] = (U16)normalizedCounter[s];
         }   }   }
-        memcpy(dt, &DTableH, sizeof(DTableH));
+        ZSTD_memcpy(dt, &DTableH, sizeof(DTableH));
     }
 
     /* Spread symbols */
-    {   U32 const tableMask = tableSize-1;
+    assert(tableSize <= 512);
+    /* Specialized symbol spreading for the case when there are
+     * no low probability (-1 count) symbols. When compressing
+     * small blocks we avoid low probability symbols to hit this
+     * case, since header decoding speed matters more.
+     */
+    if (highThreshold == tableSize - 1) {
+        size_t const tableMask = tableSize-1;
+        size_t const step = FSE_TABLESTEP(tableSize);
+        /* First lay down the symbols in order.
+         * We use a uint64_t to lay down 8 bytes at a time. This reduces branch
+         * misses since small blocks generally have small table logs, so nearly
+         * all symbols have counts <= 8. We ensure we have 8 bytes at the end of
+         * our buffer to handle the over-write.
+         */
+        {
+            U64 const add = 0x0101010101010101ull;
+            size_t pos = 0;
+            U64 sv = 0;
+            U32 s;
+            for (s=0; s<maxSV1; ++s, sv += add) {
+                int i;
+                int const n = normalizedCounter[s];
+                MEM_write64(spread + pos, sv);
+                for (i = 8; i < n; i += 8) {
+                    MEM_write64(spread + pos + i, sv);
+                }
+                pos += n;
+            }
+        }
+        /* Now we spread those positions across the table.
+         * The benefit of doing it in two stages is that we avoid the the
+         * variable size inner loop, which caused lots of branch misses.
+         * Now we can run through all the positions without any branch misses.
+         * We unroll the loop twice, since that is what emperically worked best.
+         */
+        {
+            size_t position = 0;
+            size_t s;
+            size_t const unroll = 2;
+            assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */
+            for (s = 0; s < (size_t)tableSize; s += unroll) {
+                size_t u;
+                for (u = 0; u < unroll; ++u) {
+                    size_t const uPosition = (position + (u * step)) & tableMask;
+                    tableDecode[uPosition].baseValue = spread[s + u];
+                }
+                position = (position + (unroll * step)) & tableMask;
+            }
+            assert(position == 0);
+        }
+    } else {
+        U32 const tableMask = tableSize-1;
         U32 const step = FSE_TABLESTEP(tableSize);
         U32 s, position = 0;
         for (s=0; s<maxSV1; s++) {
             int i;
-            for (i=0; i<normalizedCounter[s]; i++) {
+            int const n = normalizedCounter[s];
+            for (i=0; i<n; i++) {
                 tableDecode[position].baseValue = s;
                 position = (position + step) & tableMask;
                 while (position > highThreshold) position = (position + step) & tableMask;   /* lowprob area */
@@ -414,7 +470,8 @@ ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
     }
 
     /* Build Decoding table */
-    {   U32 u;
+    {
+        U32 u;
         for (u=0; u<tableSize; u++) {
             U32 const symbol = tableDecode[u].baseValue;
             U32 const nextState = symbolNext[symbol]++;
@@ -423,7 +480,46 @@ ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
             assert(nbAdditionalBits[symbol] < 255);
             tableDecode[u].nbAdditionalBits = (BYTE)nbAdditionalBits[symbol];
             tableDecode[u].baseValue = baseValue[symbol];
-    }   }
+        }
+    }
+}
+
+/* Avoids the FORCE_INLINE of the _body() function. */
+static void ZSTD_buildFSETable_body_default(ZSTD_seqSymbol* dt,
+            const short* normalizedCounter, unsigned maxSymbolValue,
+            const U32* baseValue, const U32* nbAdditionalBits,
+            unsigned tableLog, void* wksp, size_t wkspSize)
+{
+    ZSTD_buildFSETable_body(dt, normalizedCounter, maxSymbolValue,
+            baseValue, nbAdditionalBits, tableLog, wksp, wkspSize);
+}
+
+#if DYNAMIC_BMI2
+TARGET_ATTRIBUTE("bmi2") static void ZSTD_buildFSETable_body_bmi2(ZSTD_seqSymbol* dt,
+            const short* normalizedCounter, unsigned maxSymbolValue,
+            const U32* baseValue, const U32* nbAdditionalBits,
+            unsigned tableLog, void* wksp, size_t wkspSize)
+{
+    ZSTD_buildFSETable_body(dt, normalizedCounter, maxSymbolValue,
+            baseValue, nbAdditionalBits, tableLog, wksp, wkspSize);
+}
+#endif
+
+void ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
+            const short* normalizedCounter, unsigned maxSymbolValue,
+            const U32* baseValue, const U32* nbAdditionalBits,
+            unsigned tableLog, void* wksp, size_t wkspSize, int bmi2)
+{
+#if DYNAMIC_BMI2
+    if (bmi2) {
+        ZSTD_buildFSETable_body_bmi2(dt, normalizedCounter, maxSymbolValue,
+                baseValue, nbAdditionalBits, tableLog, wksp, wkspSize);
+        return;
+    }
+#endif
+    (void)bmi2;
+    ZSTD_buildFSETable_body_default(dt, normalizedCounter, maxSymbolValue,
+            baseValue, nbAdditionalBits, tableLog, wksp, wkspSize);
 }
 
 
@@ -435,7 +531,8 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb
                                  const void* src, size_t srcSize,
                                  const U32* baseValue, const U32* nbAdditionalBits,
                                  const ZSTD_seqSymbol* defaultTable, U32 flagRepeatTable,
-                                 int ddictIsCold, int nbSeq)
+                                 int ddictIsCold, int nbSeq, U32* wksp, size_t wkspSize,
+                                 int bmi2)
 {
     switch(type)
     {
@@ -467,7 +564,7 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb
             size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize);
             RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected, "");
             RETURN_ERROR_IF(tableLog > maxLog, corruption_detected, "");
-            ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog);
+            ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog, wksp, wkspSize, bmi2);
             *DTablePtr = DTableSpace;
             return headerSize;
         }
@@ -480,7 +577,7 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb
 size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
                              const void* src, size_t srcSize)
 {
-    const BYTE* const istart = (const BYTE* const)src;
+    const BYTE* const istart = (const BYTE*)src;
     const BYTE* const iend = istart + srcSize;
     const BYTE* ip = istart;
     int nbSeq;
@@ -499,7 +596,8 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
     if (nbSeq > 0x7F) {
         if (nbSeq == 0xFF) {
             RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong, "");
-            nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2;
+            nbSeq = MEM_readLE16(ip) + LONGNBSEQ;
+            ip+=2;
         } else {
             RETURN_ERROR_IF(ip >= iend, srcSize_wrong, "");
             nbSeq = ((nbSeq-0x80)<<8) + *ip++;
@@ -520,7 +618,9 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
                                                       ip, iend-ip,
                                                       LL_base, LL_bits,
                                                       LL_defaultDTable, dctx->fseEntropy,
-                                                      dctx->ddictIsCold, nbSeq);
+                                                      dctx->ddictIsCold, nbSeq,
+                                                      dctx->workspace, sizeof(dctx->workspace),
+                                                      dctx->bmi2);
             RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected, "ZSTD_buildSeqTable failed");
             ip += llhSize;
         }
@@ -530,7 +630,9 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
                                                       ip, iend-ip,
                                                       OF_base, OF_bits,
                                                       OF_defaultDTable, dctx->fseEntropy,
-                                                      dctx->ddictIsCold, nbSeq);
+                                                      dctx->ddictIsCold, nbSeq,
+                                                      dctx->workspace, sizeof(dctx->workspace),
+                                                      dctx->bmi2);
             RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected, "ZSTD_buildSeqTable failed");
             ip += ofhSize;
         }
@@ -540,7 +642,9 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
                                                       ip, iend-ip,
                                                       ML_base, ML_bits,
                                                       ML_defaultDTable, dctx->fseEntropy,
-                                                      dctx->ddictIsCold, nbSeq);
+                                                      dctx->ddictIsCold, nbSeq,
+                                                      dctx->workspace, sizeof(dctx->workspace),
+                                                      dctx->bmi2);
             RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected, "ZSTD_buildSeqTable failed");
             ip += mlhSize;
         }
@@ -554,7 +658,6 @@ typedef struct {
     size_t litLength;
     size_t matchLength;
     size_t offset;
-    const BYTE* match;
 } seq_t;
 
 typedef struct {
@@ -568,9 +671,6 @@ typedef struct {
     ZSTD_fseState stateOffb;
     ZSTD_fseState stateML;
     size_t prevOffset[ZSTD_REP_NUM];
-    const BYTE* prefixStart;
-    const BYTE* dictEnd;
-    size_t pos;
 } seqState_t;
 
 /*! ZSTD_overlapCopy8() :
@@ -686,12 +786,12 @@ size_t ZSTD_execSequenceEnd(BYTE* op,
         RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, "");
         match = dictEnd - (prefixStart-match);
         if (match + sequence.matchLength <= dictEnd) {
-            memmove(oLitEnd, match, sequence.matchLength);
+            ZSTD_memmove(oLitEnd, match, sequence.matchLength);
             return sequenceLength;
         }
         /* span extDict & currentPrefixSegment */
         {   size_t const length1 = dictEnd - match;
-            memmove(oLitEnd, match, length1);
+            ZSTD_memmove(oLitEnd, match, length1);
             op = oLitEnd + length1;
             sequence.matchLength -= length1;
             match = prefixStart;
@@ -752,12 +852,12 @@ size_t ZSTD_execSequence(BYTE* op,
         RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, "");
         match = dictEnd + (match - prefixStart);
         if (match + sequence.matchLength <= dictEnd) {
-            memmove(oLitEnd, match, sequence.matchLength);
+            ZSTD_memmove(oLitEnd, match, sequence.matchLength);
             return sequenceLength;
         }
         /* span extDict & currentPrefixSegment */
         {   size_t const length1 = dictEnd - match;
-            memmove(oLitEnd, match, length1);
+            ZSTD_memmove(oLitEnd, match, length1);
             op = oLitEnd + length1;
             sequence.matchLength -= length1;
             match = prefixStart;
@@ -832,10 +932,9 @@ ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, ZSTD
         : 0)
 
 typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
-typedef enum { ZSTD_p_noPrefetch=0, ZSTD_p_prefetch=1 } ZSTD_prefetch_e;
 
 FORCE_INLINE_TEMPLATE seq_t
-ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, const ZSTD_prefetch_e prefetch)
+ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets)
 {
     seq_t seq;
     ZSTD_seqSymbol const llDInfo = seqState->stateLL.table[seqState->stateLL.state];
@@ -910,14 +1009,6 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c
     DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u",
                 (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
 
-    if (prefetch == ZSTD_p_prefetch) {
-        size_t const pos = seqState->pos + seq.litLength;
-        const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart;
-        seq.match = matchBase + pos - seq.offset;  /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
-                                                    * No consequence though : no memory access will occur, offset is only used for prefetching */
-        seqState->pos = pos + seq.matchLength;
-    }
-
     /* ANS state update
      * gcc-9.0.0 does 2.5% worse with ZSTD_updateFseStateWithDInfo().
      * clang-9.2.0 does 7% worse with ZSTD_updateFseState().
@@ -948,7 +1039,7 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c
 }
 
 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-static int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd)
+MEM_STATIC int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd)
 {
     size_t const windowSize = dctx->fParams.windowSize;
     /* No dictionary used. */
@@ -969,6 +1060,7 @@ MEM_STATIC void ZSTD_assertValidSequence(
         seq_t const seq,
         BYTE const* prefixStart, BYTE const* virtualStart)
 {
+#if DEBUGLEVEL >= 1
     size_t const windowSize = dctx->fParams.windowSize;
     size_t const sequenceSize = seq.litLength + seq.matchLength;
     BYTE const* const oLitEnd = op + seq.litLength;
@@ -986,6 +1078,9 @@ MEM_STATIC void ZSTD_assertValidSequence(
         /* Offset must be within our window. */
         assert(seq.offset <= windowSize);
     }
+#else
+    (void)dctx, (void)op, (void)oend, (void)seq, (void)prefixStart, (void)virtualStart;
+#endif
 }
 #endif
 
@@ -1000,7 +1095,7 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
 {
     const BYTE* ip = (const BYTE*)seqStart;
     const BYTE* const iend = ip + seqSize;
-    BYTE* const ostart = (BYTE* const)dst;
+    BYTE* const ostart = (BYTE*)dst;
     BYTE* const oend = ostart + maxDstSize;
     BYTE* op = ostart;
     const BYTE* litPtr = dctx->litPtr;
@@ -1014,7 +1109,6 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
     /* Regen sequences */
     if (nbSeq) {
         seqState_t seqState;
-        size_t error = 0;
         dctx->fseEntropy = 1;
         { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
         RETURN_ERROR_IF(
@@ -1048,13 +1142,14 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
          * If you see most cycles served out of the DSB you've hit the good case.
          * If it is pretty even then you may be in an okay case.
          *
-         * I've been able to reproduce this issue on the following CPUs:
+         * This issue has been reproduced on the following CPUs:
          *   - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9
          *               Use Instruments->Counters to get DSB/MITE cycles.
          *               I never got performance swings, but I was able to
          *               go from the good case of mostly DSB to half of the
          *               cycles served from MITE.
          *   - Coffeelake: Intel i9-9900k
+         *   - Coffeelake: Intel i7-9700k
          *
          * I haven't been able to reproduce the instability or DSB misses on any
          * of the following CPUS:
@@ -1067,33 +1162,35 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
          *
          *   https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4
          */
+        __asm__(".p2align 6");
+        __asm__("nop");
         __asm__(".p2align 5");
         __asm__("nop");
+#  if __GNUC__ >= 9
+        /* better for gcc-9 and gcc-10, worse for clang and gcc-8 */
+        __asm__(".p2align 3");
+#  else
         __asm__(".p2align 4");
+#  endif
 #endif
         for ( ; ; ) {
-            seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_noPrefetch);
+            seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset);
             size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd);
 #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
             assert(!ZSTD_isError(oneSeqSize));
             if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase);
 #endif
+            if (UNLIKELY(ZSTD_isError(oneSeqSize)))
+                return oneSeqSize;
             DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize);
+            op += oneSeqSize;
+            if (UNLIKELY(!--nbSeq))
+                break;
             BIT_reloadDStream(&(seqState.DStream));
-            /* gcc and clang both don't like early returns in this loop.
-             * gcc doesn't like early breaks either.
-             * Instead save an error and report it at the end.
-             * When there is an error, don't increment op, so we don't
-             * overwrite.
-             */
-            if (UNLIKELY(ZSTD_isError(oneSeqSize))) error = oneSeqSize;
-            else op += oneSeqSize;
-            if (UNLIKELY(!--nbSeq)) break;
         }
 
         /* check if reached exact end */
         DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq);
-        if (ZSTD_isError(error)) return error;
         RETURN_ERROR_IF(nbSeq, corruption_detected, "");
         RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, "");
         /* save reps for next block */
@@ -1104,7 +1201,7 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
     {   size_t const lastLLSize = litEnd - litPtr;
         RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
         if (op != NULL) {
-            memcpy(op, litPtr, lastLLSize);
+            ZSTD_memcpy(op, litPtr, lastLLSize);
             op += lastLLSize;
         }
     }
@@ -1124,6 +1221,24 @@ ZSTD_decompressSequences_default(ZSTD_DCtx* dctx,
 #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
 
 #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
+
+FORCE_INLINE_TEMPLATE size_t
+ZSTD_prefetchMatch(size_t prefetchPos, seq_t const sequence,
+                   const BYTE* const prefixStart, const BYTE* const dictEnd)
+{
+    prefetchPos += sequence.litLength;
+    {   const BYTE* const matchBase = (sequence.offset > prefetchPos) ? dictEnd : prefixStart;
+        const BYTE* const match = matchBase + prefetchPos - sequence.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
+                                                                              * No consequence though : memory address is only used for prefetching, not for dereferencing */
+        PREFETCH_L1(match); PREFETCH_L1(match+CACHELINE_SIZE);   /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
+    }
+    return prefetchPos + sequence.matchLength;
+}
+
+/* This decoding function employs prefetching
+ * to reduce latency impact of cache misses.
+ * It's generally employed when block contains a significant portion of long-distance matches
+ * or when coupled with a "cold" dictionary */
 FORCE_INLINE_TEMPLATE size_t
 ZSTD_decompressSequencesLong_body(
                                ZSTD_DCtx* dctx,
@@ -1134,7 +1249,7 @@ ZSTD_decompressSequencesLong_body(
 {
     const BYTE* ip = (const BYTE*)seqStart;
     const BYTE* const iend = ip + seqSize;
-    BYTE* const ostart = (BYTE* const)dst;
+    BYTE* const ostart = (BYTE*)dst;
     BYTE* const oend = ostart + maxDstSize;
     BYTE* op = ostart;
     const BYTE* litPtr = dctx->litPtr;
@@ -1146,18 +1261,17 @@ ZSTD_decompressSequencesLong_body(
 
     /* Regen sequences */
     if (nbSeq) {
-#define STORED_SEQS 4
+#define STORED_SEQS 8
 #define STORED_SEQS_MASK (STORED_SEQS-1)
-#define ADVANCED_SEQS 4
+#define ADVANCED_SEQS STORED_SEQS
         seq_t sequences[STORED_SEQS];
         int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS);
         seqState_t seqState;
         int seqNb;
+        size_t prefetchPos = (size_t)(op-prefixStart); /* track position relative to prefixStart */
+
         dctx->fseEntropy = 1;
         { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
-        seqState.prefixStart = prefixStart;
-        seqState.pos = (size_t)(op-prefixStart);
-        seqState.dictEnd = dictEnd;
         assert(dst != NULL);
         assert(iend >= ip);
         RETURN_ERROR_IF(
@@ -1169,21 +1283,23 @@ ZSTD_decompressSequencesLong_body(
 
         /* prepare in advance */
         for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNb<seqAdvance); seqNb++) {
-            sequences[seqNb] = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_prefetch);
-            PREFETCH_L1(sequences[seqNb].match); PREFETCH_L1(sequences[seqNb].match + sequences[seqNb].matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
+            seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset);
+            prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd);
+            sequences[seqNb] = sequence;
         }
         RETURN_ERROR_IF(seqNb<seqAdvance, corruption_detected, "");
 
         /* decode and decompress */
         for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && (seqNb<nbSeq) ; seqNb++) {
-            seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_prefetch);
+            seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset);
             size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
 #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
             assert(!ZSTD_isError(oneSeqSize));
             if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart);
 #endif
             if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
-            PREFETCH_L1(sequence.match); PREFETCH_L1(sequence.match + sequence.matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
+
+            prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd);
             sequences[seqNb & STORED_SEQS_MASK] = sequence;
             op += oneSeqSize;
         }
@@ -1209,7 +1325,7 @@ ZSTD_decompressSequencesLong_body(
     {   size_t const lastLLSize = litEnd - litPtr;
         RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
         if (op != NULL) {
-            memcpy(op, litPtr, lastLLSize);
+            ZSTD_memcpy(op, litPtr, lastLLSize);
             op += lastLLSize;
         }
     }
@@ -1409,9 +1525,9 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
 }
 
 
-void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
+void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize)
 {
-    if (dst != dctx->previousDstEnd) {   /* not contiguous */
+    if (dst != dctx->previousDstEnd && dstSize > 0) {   /* not contiguous */
         dctx->dictEnd = dctx->previousDstEnd;
         dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
         dctx->prefixStart = dst;
@@ -1425,7 +1541,7 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx,
                       const void* src, size_t srcSize)
 {
     size_t dSize;
-    ZSTD_checkContinuity(dctx, dst);
+    ZSTD_checkContinuity(dctx, dst, dstCapacity);
     dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0);
     dctx->previousDstEnd = (char*)dst + dSize;
     return dSize;
index bf39b73..049a0cd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -15,7 +15,7 @@
 /*-*******************************************************
  *  Dependencies
  *********************************************************/
-#include <stddef.h>   /* size_t */
+#include "../common/zstd_deps.h"   /* size_t */
 #include "../zstd.h"    /* DCtx, and some public functions */
 #include "../common/zstd_internal.h"  /* blockProperties_t, and some public functions */
 #include "zstd_decompress_internal.h"  /* ZSTD_seqSymbol */
@@ -48,12 +48,15 @@ size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
  * this function must be called with valid parameters only
  * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.)
  * in which case it cannot fail.
+ * The workspace must be 4-byte aligned and at least ZSTD_BUILD_FSE_TABLE_WKSP_SIZE bytes, which is
+ * defined in zstd_decompress_internal.h.
  * Internal use only.
  */
 void ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
              const short* normalizedCounter, unsigned maxSymbolValue,
              const U32* baseValue, const U32* nbAdditionalBits,
-                   unsigned tableLog);
+                   unsigned tableLog, void* wksp, size_t wkspSize,
+                   int bmi2);
 
 
 #endif /* ZSTD_DEC_BLOCK_H */
index 9ad96c5..ebda0c9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
 /*-*******************************************************
  *  Constants
  *********************************************************/
-static const U32 LL_base[MaxLL+1] = {
+static UNUSED_ATTR const U32 LL_base[MaxLL+1] = {
                  0,    1,    2,     3,     4,     5,     6,      7,
                  8,    9,   10,    11,    12,    13,    14,     15,
                 16,   18,   20,    22,    24,    28,    32,     40,
                 48,   64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
                 0x2000, 0x4000, 0x8000, 0x10000 };
 
-static const U32 OF_base[MaxOff+1] = {
+static UNUSED_ATTR const U32 OF_base[MaxOff+1] = {
                  0,        1,       1,       5,     0xD,     0x1D,     0x3D,     0x7D,
                  0xFD,   0x1FD,   0x3FD,   0x7FD,   0xFFD,   0x1FFD,   0x3FFD,   0x7FFD,
                  0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
                  0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD };
 
-static const U32 OF_bits[MaxOff+1] = {
+static UNUSED_ATTR const U32 OF_bits[MaxOff+1] = {
                      0,  1,  2,  3,  4,  5,  6,  7,
                      8,  9, 10, 11, 12, 13, 14, 15,
                     16, 17, 18, 19, 20, 21, 22, 23,
                     24, 25, 26, 27, 28, 29, 30, 31 };
 
-static const U32 ML_base[MaxML+1] = {
+static UNUSED_ATTR const U32 ML_base[MaxML+1] = {
                      3,  4,  5,    6,     7,     8,     9,    10,
                     11, 12, 13,   14,    15,    16,    17,    18,
                     19, 20, 21,   22,    23,    24,    25,    26,
@@ -73,12 +73,16 @@ static const U32 ML_base[MaxML+1] = {
 
  #define SEQSYMBOL_TABLE_SIZE(log)   (1 + (1 << (log)))
 
+#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64))
+#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32))
+
 typedef struct {
     ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)];    /* Note : Space reserved for FSE Tables */
     ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)];   /* is also used as temporary workspace while building hufTable during DDict creation */
     ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)];    /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */
     HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)];  /* can accommodate HUF_decompress4X */
     U32 rep[ZSTD_REP_NUM];
+    U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32];
 } ZSTD_entropyDTables_t;
 
 typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader,
@@ -95,10 +99,12 @@ typedef enum {
     ZSTD_use_once = 1            /* Use the dictionary once and set to ZSTD_dont_use */
 } ZSTD_dictUses_e;
 
-typedef enum {
-    ZSTD_obm_buffered = 0,  /* Buffer the output */
-    ZSTD_obm_stable = 1     /* ZSTD_outBuffer is stable */
-} ZSTD_outBufferMode_e;
+/* Hashset for storing references to multiple ZSTD_DDict within ZSTD_DCtx */
+typedef struct {
+    const ZSTD_DDict** ddictPtrTable;
+    size_t ddictPtrTableSize;
+    size_t ddictPtrCount;
+} ZSTD_DDictHashSet;
 
 struct ZSTD_DCtx_s
 {
@@ -114,6 +120,7 @@ struct ZSTD_DCtx_s
     const void* dictEnd;          /* end of previous segment */
     size_t expected;
     ZSTD_frameHeader fParams;
+    U64 processedCSize;
     U64 decodedSize;
     blockType_e bType;            /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */
     ZSTD_dStage stage;
@@ -122,6 +129,8 @@ struct ZSTD_DCtx_s
     XXH64_state_t xxhState;
     size_t headerSize;
     ZSTD_format_e format;
+    ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum;   /* User specified: if == 1, will ignore checksums in compressed frame. Default == 0 */
+    U32 validateChecksum;         /* if == 1, will validate checksum. Is == 1 if (fParams.checksumFlag == 1) and (forceIgnoreChecksum == 0). */
     const BYTE* litPtr;
     ZSTD_customMem customMem;
     size_t litSize;
@@ -135,6 +144,8 @@ struct ZSTD_DCtx_s
     U32 dictID;
     int ddictIsCold;             /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */
     ZSTD_dictUses_e dictUses;
+    ZSTD_DDictHashSet* ddictSet;                    /* Hash set for multiple ddicts */
+    ZSTD_refMultipleDDicts_e refMultipleDDicts;     /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */
 
     /* streaming */
     ZSTD_dStreamStage streamStage;
@@ -152,7 +163,7 @@ struct ZSTD_DCtx_s
     U32 legacyVersion;
     U32 hostageByte;
     int noForwardProgress;
-    ZSTD_outBufferMode_e outBufferMode;
+    ZSTD_bufferMode_e outBufferMode;
     ZSTD_outBuffer expectedOutBuffer;
 
     /* workspace */
@@ -165,6 +176,11 @@ struct ZSTD_DCtx_s
     void const* dictContentBeginForFuzzing;
     void const* dictContentEndForFuzzing;
 #endif
+
+    /* Tracing */
+#if ZSTD_TRACE
+    ZSTD_TraceCtx traceCtx;
+#endif
 };  /* typedef'd to ZSTD_DCtx within "zstd.h" */
 
 
@@ -183,7 +199,7 @@ size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
  *  If yes, do nothing (continue on current segment).
  *  If not, classify previous segment as "external dictionary", and start a new segment.
  *  This function cannot fail. */
-void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst);
+void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize);
 
 
 #endif /* ZSTD_DECOMPRESS_INTERNAL_H */
index 03cb14a..b83ea0f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
index 579bc4d..e7d01a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
index 2d20b13..2e72267 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
index d3c49e8..d73c0f3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
index da54ef1..8364444 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
 #include <string.h> /* memset */
 #include <time.h>   /* clock */
 
+#ifndef ZDICT_STATIC_LINKING_ONLY
+#  define ZDICT_STATIC_LINKING_ONLY
+#endif
+
 #include "../common/mem.h" /* read */
 #include "../common/pool.h"
 #include "../common/threading.h"
-#include "cover.h"
 #include "../common/zstd_internal.h" /* includes zstd.h */
-#ifndef ZDICT_STATIC_LINKING_ONLY
-#define ZDICT_STATIC_LINKING_ONLY
-#endif
-#include "zdict.h"
+#include "../zdict.h"
+#include "cover.h"
 
 /*-*************************************
 *  Constants
 ***************************************/
 #define COVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB))
-#define DEFAULT_SPLITPOINT 1.0
+#define COVER_DEFAULT_SPLITPOINT 1.0
 
 /*-*************************************
 *  Console display
 ***************************************/
+#ifndef LOCALDISPLAYLEVEL
 static int g_displayLevel = 2;
+#endif
+#undef  DISPLAY
 #define DISPLAY(...)                                                           \
   {                                                                            \
     fprintf(stderr, __VA_ARGS__);                                              \
     fflush(stderr);                                                            \
   }
+#undef  LOCALDISPLAYLEVEL
 #define LOCALDISPLAYLEVEL(displayLevel, l, ...)                                \
   if (displayLevel >= l) {                                                     \
     DISPLAY(__VA_ARGS__);                                                      \
   } /* 0 : no display;   1: errors;   2: default;  3: details;  4: debug */
+#undef  DISPLAYLEVEL
 #define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__)
 
+#ifndef LOCALDISPLAYUPDATE
+static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100;
+static clock_t g_time = 0;
+#endif
+#undef  LOCALDISPLAYUPDATE
 #define LOCALDISPLAYUPDATE(displayLevel, l, ...)                               \
   if (displayLevel >= l) {                                                     \
-    if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) {             \
+    if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) {             \
       g_time = clock();                                                        \
       DISPLAY(__VA_ARGS__);                                                    \
     }                                                                          \
   }
+#undef  DISPLAYUPDATE
 #define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__)
-static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
-static clock_t g_time = 0;
 
 /*-*************************************
 * Hash table
@@ -120,9 +130,9 @@ static int COVER_map_init(COVER_map_t *map, U32 size) {
 /**
  * Internal hash function
  */
-static const U32 prime4bytes = 2654435761U;
+static const U32 COVER_prime4bytes = 2654435761U;
 static U32 COVER_map_hash(COVER_map_t *map, U32 key) {
-  return (key * prime4bytes) >> (32 - map->sizeLog);
+  return (key * COVER_prime4bytes) >> (32 - map->sizeLog);
 }
 
 /**
@@ -215,7 +225,7 @@ typedef struct {
 } COVER_ctx_t;
 
 /* We need a global context for qsort... */
-static COVER_ctx_t *g_ctx = NULL;
+static COVER_ctx_t *g_coverCtx = NULL;
 
 /*-*************************************
 *  Helper functions
@@ -258,11 +268,11 @@ static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) {
 
 /**
  * Same as COVER_cmp() except ties are broken by pointer value
- * NOTE: g_ctx must be set to call this function.  A global is required because
+ * NOTE: g_coverCtx must be set to call this function.  A global is required because
  * qsort doesn't take an opaque pointer.
  */
-static int COVER_strict_cmp(const void *lp, const void *rp) {
-  int result = COVER_cmp(g_ctx, lp, rp);
+static int WIN_CDECL COVER_strict_cmp(const void *lp, const void *rp) {
+  int result = COVER_cmp(g_coverCtx, lp, rp);
   if (result == 0) {
     result = lp < rp ? -1 : 1;
   }
@@ -271,8 +281,8 @@ static int COVER_strict_cmp(const void *lp, const void *rp) {
 /**
  * Faster version for d <= 8.
  */
-static int COVER_strict_cmp8(const void *lp, const void *rp) {
-  int result = COVER_cmp8(g_ctx, lp, rp);
+static int WIN_CDECL COVER_strict_cmp8(const void *lp, const void *rp) {
+  int result = COVER_cmp8(g_coverCtx, lp, rp);
   if (result == 0) {
     result = lp < rp ? -1 : 1;
   }
@@ -603,7 +613,7 @@ static size_t COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer,
     /* qsort doesn't take an opaque pointer, so pass as a global.
      * On OpenBSD qsort() is not guaranteed to be stable, their mergesort() is.
      */
-    g_ctx = ctx;
+    g_coverCtx = ctx;
 #if defined(__OpenBSD__)
     mergesort(ctx->suffix, ctx->suffixSize, sizeof(U32),
           (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp));
@@ -946,7 +956,7 @@ void COVER_dictSelectionFree(COVER_dictSelection_t selection){
   free(selection.dictContent);
 }
 
-COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent,
+COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBufferCapacity,
         size_t dictContentSize, const BYTE* samplesBuffer, const size_t* samplesSizes, unsigned nbFinalizeSamples,
         size_t nbCheckSamples, size_t nbSamples, ZDICT_cover_params_t params, size_t* offsets, size_t totalCompressedSize) {
 
@@ -954,8 +964,8 @@ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent,
   size_t largestCompressed = 0;
   BYTE* customDictContentEnd = customDictContent + dictContentSize;
 
-  BYTE * largestDictbuffer = (BYTE *)malloc(dictContentSize);
-  BYTE * candidateDictBuffer = (BYTE *)malloc(dictContentSize);
+  BYTE * largestDictbuffer = (BYTE *)malloc(dictBufferCapacity);
+  BYTE * candidateDictBuffer = (BYTE *)malloc(dictBufferCapacity);
   double regressionTolerance = ((double)params.shrinkDictMaxRegression / 100.0) + 1.00;
 
   if (!largestDictbuffer || !candidateDictBuffer) {
@@ -967,7 +977,7 @@ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent,
   /* Initial dictionary size and compressed size */
   memcpy(largestDictbuffer, customDictContent, dictContentSize);
   dictContentSize = ZDICT_finalizeDictionary(
-    largestDictbuffer, dictContentSize, customDictContent, dictContentSize,
+    largestDictbuffer, dictBufferCapacity, customDictContent, dictContentSize,
     samplesBuffer, samplesSizes, nbFinalizeSamples, params.zParams);
 
   if (ZDICT_isError(dictContentSize)) {
@@ -1001,7 +1011,7 @@ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent,
   while (dictContentSize < largestDict) {
     memcpy(candidateDictBuffer, largestDictbuffer, largestDict);
     dictContentSize = ZDICT_finalizeDictionary(
-      candidateDictBuffer, dictContentSize, customDictContentEnd - dictContentSize, dictContentSize,
+      candidateDictBuffer, dictBufferCapacity, customDictContentEnd - dictContentSize, dictContentSize,
       samplesBuffer, samplesSizes, nbFinalizeSamples, params.zParams);
 
     if (ZDICT_isError(dictContentSize)) {
@@ -1053,18 +1063,19 @@ typedef struct COVER_tryParameters_data_s {
  * This function is thread safe if zstd is compiled with multithreaded support.
  * It takes its parameters as an *OWNING* opaque pointer to support threading.
  */
-static void COVER_tryParameters(void *opaque) {
+static void COVER_tryParameters(void *opaque)
+{
   /* Save parameters as local variables */
-  COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t *)opaque;
+  COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t*)opaque;
   const COVER_ctx_t *const ctx = data->ctx;
   const ZDICT_cover_params_t parameters = data->parameters;
   size_t dictBufferCapacity = data->dictBufferCapacity;
   size_t totalCompressedSize = ERROR(GENERIC);
   /* Allocate space for hash table, dict, and freqs */
   COVER_map_t activeDmers;
-  BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity);
+  BYTE* const dict = (BYTE*)malloc(dictBufferCapacity);
   COVER_dictSelection_t selection = COVER_dictSelectionError(ERROR(GENERIC));
-  U32 *freqs = (U32 *)malloc(ctx->suffixSize * sizeof(U32));
+  U32* const freqs = (U32*)malloc(ctx->suffixSize * sizeof(U32));
   if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) {
     DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n");
     goto _cleanup;
@@ -1079,7 +1090,7 @@ static void COVER_tryParameters(void *opaque) {
   {
     const size_t tail = COVER_buildDictionary(ctx, freqs, &activeDmers, dict,
                                               dictBufferCapacity, parameters);
-    selection = COVER_selectDict(dict + tail, dictBufferCapacity - tail,
+    selection = COVER_selectDict(dict + tail, dictBufferCapacity, dictBufferCapacity - tail,
         ctx->samples, ctx->samplesSizes, (unsigned)ctx->nbTrainSamples, ctx->nbTrainSamples, ctx->nbSamples, parameters, ctx->offsets,
         totalCompressedSize);
 
@@ -1094,19 +1105,18 @@ _cleanup:
   free(data);
   COVER_map_destroy(&activeDmers);
   COVER_dictSelectionFree(selection);
-  if (freqs) {
-    free(freqs);
-  }
+  free(freqs);
 }
 
 ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
-    void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer,
-    const size_t *samplesSizes, unsigned nbSamples,
-    ZDICT_cover_params_t *parameters) {
+    void* dictBuffer, size_t dictBufferCapacity, const void* samplesBuffer,
+    const size_t* samplesSizes, unsigned nbSamples,
+    ZDICT_cover_params_t* parameters)
+{
   /* constants */
   const unsigned nbThreads = parameters->nbThreads;
   const double splitPoint =
-      parameters->splitPoint <= 0.0 ? DEFAULT_SPLITPOINT : parameters->splitPoint;
+      parameters->splitPoint <= 0.0 ? COVER_DEFAULT_SPLITPOINT : parameters->splitPoint;
   const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d;
   const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d;
   const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k;
index f2aa0e3..1aacddd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -8,6 +8,10 @@
  * You may select, at your option, one of the above-listed licenses.
  */
 
+#ifndef ZDICT_STATIC_LINKING_ONLY
+#  define ZDICT_STATIC_LINKING_ONLY
+#endif
+
 #include <stdio.h>  /* fprintf */
 #include <stdlib.h> /* malloc, free, qsort */
 #include <string.h> /* memset */
 #include "../common/pool.h"
 #include "../common/threading.h"
 #include "../common/zstd_internal.h" /* includes zstd.h */
-#ifndef ZDICT_STATIC_LINKING_ONLY
-#define ZDICT_STATIC_LINKING_ONLY
-#endif
-#include "zdict.h"
+#include "../zdict.h"
 
 /**
  * COVER_best_t is used for two purposes:
@@ -152,6 +153,6 @@ void COVER_dictSelectionFree(COVER_dictSelection_t selection);
  * smallest dictionary within a specified regression of the compressed size
  * from the largest dictionary.
  */
- COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent,
+ COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBufferCapacity,
                        size_t dictContentSize, const BYTE* samplesBuffer, const size_t* samplesSizes, unsigned nbFinalizeSamples,
                        size_t nbCheckSamples, size_t nbSamples, ZDICT_cover_params_t params, size_t* offsets, size_t totalCompressedSize);
index ead9220..a2870fb 100644 (file)
@@ -1576,7 +1576,7 @@ note:
     /* Construct the inverse suffix array of type B* suffixes using trsort. */
     trsort(ISAb, SA, m, 1);
 
-    /* Set the sorted order of tyoe B* suffixes. */
+    /* Set the sorted order of type B* suffixes. */
     for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) {
       for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { }
       if(0 <= i) {
index 485c333..ed789f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, Facebook, Inc.
+ * Copyright (c) Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
 #include <string.h> /* memset */
 #include <time.h>   /* clock */
 
+#ifndef ZDICT_STATIC_LINKING_ONLY
+#  define ZDICT_STATIC_LINKING_ONLY
+#endif
+
 #include "../common/mem.h" /* read */
 #include "../common/pool.h"
 #include "../common/threading.h"
-#include "cover.h"
 #include "../common/zstd_internal.h" /* includes zstd.h */
-#ifndef ZDICT_STATIC_LINKING_ONLY
-#define ZDICT_STATIC_LINKING_ONLY
-#endif
-#include "zdict.h"
+#include "../compress/zstd_compress_internal.h" /* ZSTD_hash*() */
+#include "../zdict.h"
+#include "cover.h"
 
 
 /*-*************************************
@@ -33,7 +35,7 @@
 #define FASTCOVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB))
 #define FASTCOVER_MAX_F 31
 #define FASTCOVER_MAX_ACCEL 10
-#define DEFAULT_SPLITPOINT 0.75
+#define FASTCOVER_DEFAULT_SPLITPOINT 0.75
 #define DEFAULT_F 20
 #define DEFAULT_ACCEL 1
 
 /*-*************************************
 *  Console display
 ***************************************/
+#ifndef LOCALDISPLAYLEVEL
 static int g_displayLevel = 2;
+#endif
+#undef  DISPLAY
 #define DISPLAY(...)                                                           \
   {                                                                            \
     fprintf(stderr, __VA_ARGS__);                                              \
     fflush(stderr);                                                            \
   }
+#undef  LOCALDISPLAYLEVEL
 #define LOCALDISPLAYLEVEL(displayLevel, l, ...)                                \
   if (displayLevel >= l) {                                                     \
     DISPLAY(__VA_ARGS__);                                                      \
   } /* 0 : no display;   1: errors;   2: default;  3: details;  4: debug */
+#undef  DISPLAYLEVEL
 #define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__)
 
+#ifndef LOCALDISPLAYUPDATE
+static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100;
+static clock_t g_time = 0;
+#endif
+#undef  LOCALDISPLAYUPDATE
 #define LOCALDISPLAYUPDATE(displayLevel, l, ...)                               \
   if (displayLevel >= l) {                                                     \
-    if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) {             \
+    if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) {             \
       g_time = clock();                                                        \
       DISPLAY(__VA_ARGS__);                                                    \
     }                                                                          \
   }
+#undef  DISPLAYUPDATE
 #define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__)
-static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
-static clock_t g_time = 0;
 
 
 /*-*************************************
 * Hash Functions
 ***************************************/
-static const U64 prime6bytes = 227718039650203ULL;
-static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u  << (64-48)) * prime6bytes) >> (64-h)) ; }
-static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
-
-static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
-static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
-static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
-
-
 /**
- * Hash the d-byte value pointed to by p and mod 2^f
+ * Hash the d-byte value pointed to by p and mod 2^f into the frequency vector
  */
-static size_t FASTCOVER_hashPtrToIndex(const void* p, U32 h, unsigned d) {
+static size_t FASTCOVER_hashPtrToIndex(const void* p, U32 f, unsigned d) {
   if (d == 6) {
-    return ZSTD_hash6Ptr(p, h) & ((1 << h) - 1);
+    return ZSTD_hash6Ptr(p, f);
   }
-  return ZSTD_hash8Ptr(p, h) & ((1 << h) - 1);
+  return ZSTD_hash8Ptr(p, f);
 }
 
 
@@ -461,20 +463,20 @@ typedef struct FASTCOVER_tryParameters_data_s {
  * This function is thread safe if zstd is compiled with multithreaded support.
  * It takes its parameters as an *OWNING* opaque pointer to support threading.
  */
-static void FASTCOVER_tryParameters(void *opaque)
+static void FASTCOVER_tryParameters(voidopaque)
 {
   /* Save parameters as local variables */
-  FASTCOVER_tryParameters_data_t *const data = (FASTCOVER_tryParameters_data_t *)opaque;
+  FASTCOVER_tryParameters_data_t *const data = (FASTCOVER_tryParameters_data_t*)opaque;
   const FASTCOVER_ctx_t *const ctx = data->ctx;
   const ZDICT_cover_params_t parameters = data->parameters;
   size_t dictBufferCapacity = data->dictBufferCapacity;
   size_t totalCompressedSize = ERROR(GENERIC);
   /* Initialize array to keep track of frequency of dmer within activeSegment */
-  U16* segmentFreqs = (U16 *)calloc(((U64)1 << ctx->f), sizeof(U16));
+  U16* segmentFreqs = (U16*)calloc(((U64)1 << ctx->f), sizeof(U16));
   /* Allocate space for hash table, dict, and freqs */
-  BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity);
+  BYTE *const dict = (BYTE*)malloc(dictBufferCapacity);
   COVER_dictSelection_t selection = COVER_dictSelectionError(ERROR(GENERIC));
-  U32 *freqs = (U32*) malloc(((U64)1 << ctx->f) * sizeof(U32));
+  U32freqs = (U32*) malloc(((U64)1 << ctx->f) * sizeof(U32));
   if (!segmentFreqs || !dict || !freqs) {
     DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n");
     goto _cleanup;
@@ -486,7 +488,7 @@ static void FASTCOVER_tryParameters(void *opaque)
                                                     parameters, segmentFreqs);
 
     const unsigned nbFinalizeSamples = (unsigned)(ctx->nbTrainSamples * ctx->accelParams.finalize / 100);
-    selection = COVER_selectDict(dict + tail, dictBufferCapacity - tail,
+    selection = COVER_selectDict(dict + tail, dictBufferCapacity, dictBufferCapacity - tail,
          ctx->samples, ctx->samplesSizes, nbFinalizeSamples, ctx->nbTrainSamples, ctx->nbSamples, parameters, ctx->offsets,
          totalCompressedSize);
 
@@ -617,7 +619,7 @@ ZDICT_optimizeTrainFromBuffer_fastCover(
     /* constants */
     const unsigned nbThreads = parameters->nbThreads;
     const double splitPoint =
-        parameters->splitPoint <= 0.0 ? DEFAULT_SPLITPOINT : parameters->splitPoint;
+        parameters->splitPoint <= 0.0 ? FASTCOVER_DEFAULT_SPLITPOINT : parameters->splitPoint;
     const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d;
     const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d;
     const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k;
index 6d0b042..459cbe4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
 /* Unix Large Files support (>4GB) */
 #define _FILE_OFFSET_BITS 64
 #if (defined(__sun__) && (!defined(__LP64__)))   /* Sun Solaris 32-bits requires specific definitions */
+#  ifndef _LARGEFILE_SOURCE
 #  define _LARGEFILE_SOURCE
+#  endif
 #elif ! defined(__LP64__)                        /* No point defining Large file for 64 bit */
+#  ifndef _LARGEFILE64_SOURCE
 #  define _LARGEFILE64_SOURCE
+#  endif
 #endif
 
 
 #include <stdio.h>         /* fprintf, fopen, ftello64 */
 #include <time.h>          /* clock */
 
+#ifndef ZDICT_STATIC_LINKING_ONLY
+#  define ZDICT_STATIC_LINKING_ONLY
+#endif
+#define HUF_STATIC_LINKING_ONLY
+
 #include "../common/mem.h"           /* read */
 #include "../common/fse.h"           /* FSE_normalizeCount, FSE_writeNCount */
-#define HUF_STATIC_LINKING_ONLY
 #include "../common/huf.h"           /* HUF_buildCTable, HUF_writeCTable */
 #include "../common/zstd_internal.h" /* includes zstd.h */
 #include "../common/xxhash.h"        /* XXH64 */
-#include "divsufsort.h"
-#ifndef ZDICT_STATIC_LINKING_ONLY
-#  define ZDICT_STATIC_LINKING_ONLY
-#endif
-#include "zdict.h"
 #include "../compress/zstd_compress_internal.h" /* ZSTD_loadCEntropy() */
+#include "../zdict.h"
+#include "divsufsort.h"
 
 
 /*-*************************************
 
 #define NOISELENGTH 32
 
-static const int g_compressionLevel_default = 3;
 static const U32 g_selectivity_default = 9;
 
 
 /*-*************************************
 *  Console display
 ***************************************/
+#undef  DISPLAY
 #define DISPLAY(...)         { fprintf(stderr, __VA_ARGS__); fflush( stderr ); }
+#undef  DISPLAYLEVEL
 #define DISPLAYLEVEL(l, ...) if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); }    /* 0 : no display;   1: errors;   2: default;  3: details;  4: debug */
 
 static clock_t ZDICT_clockSpan(clock_t nPrevious) { return clock() - nPrevious; }
@@ -105,20 +111,17 @@ size_t ZDICT_getDictHeaderSize(const void* dictBuffer, size_t dictSize)
     size_t headerSize;
     if (dictSize <= 8 || MEM_readLE32(dictBuffer) != ZSTD_MAGIC_DICTIONARY) return ERROR(dictionary_corrupted);
 
-    {   unsigned offcodeMaxValue = MaxOff;
-        ZSTD_compressedBlockState_t* bs = (ZSTD_compressedBlockState_t*)malloc(sizeof(ZSTD_compressedBlockState_t));
+    {   ZSTD_compressedBlockState_t* bs = (ZSTD_compressedBlockState_t*)malloc(sizeof(ZSTD_compressedBlockState_t));
         U32* wksp = (U32*)malloc(HUF_WORKSPACE_SIZE);
-        short* offcodeNCount = (short*)malloc((MaxOff+1)*sizeof(short));
-        if (!bs || !wksp || !offcodeNCount) {
+        if (!bs || !wksp) {
             headerSize = ERROR(memory_allocation);
         } else {
             ZSTD_reset_compressedBlockState(bs);
-            headerSize = ZSTD_loadCEntropy(bs, wksp, offcodeNCount, &offcodeMaxValue, dictBuffer, dictSize);
+            headerSize = ZSTD_loadCEntropy(bs, wksp, dictBuffer, dictSize);
         }
 
         free(bs);
         free(wksp);
-        free(offcodeNCount);
     }
 
     return headerSize;
@@ -532,6 +535,7 @@ static size_t ZDICT_trainBuffer_legacy(dictItem* dictList, U32 dictListSize,
     clock_t displayClock = 0;
     clock_t const refreshRate = CLOCKS_PER_SEC * 3 / 10;
 
+#   undef  DISPLAYUPDATE
 #   define DISPLAYUPDATE(l, ...) if (notificationLevel>=l) { \
             if (ZDICT_clockSpan(displayClock) > refreshRate)  \
             { displayClock = clock(); DISPLAY(__VA_ARGS__); \
@@ -706,7 +710,7 @@ static void ZDICT_flatLit(unsigned* countLit)
 
 #define OFFCODE_MAX 30  /* only applicable to first block */
 static size_t ZDICT_analyzeEntropy(void*  dstBuffer, size_t maxDstSize,
-                                   unsigned compressionLevel,
+                                   int compressionLevel,
                              const void*  srcBuffer, const size_t* fileSizes, unsigned nbFiles,
                              const void* dictBuffer, size_t  dictBufferSize,
                                    unsigned notificationLevel)
@@ -741,7 +745,7 @@ static size_t ZDICT_analyzeEntropy(void*  dstBuffer, size_t maxDstSize,
     memset(repOffset, 0, sizeof(repOffset));
     repOffset[1] = repOffset[4] = repOffset[8] = 1;
     memset(bestRepOffset, 0, sizeof(bestRepOffset));
-    if (compressionLevel==0) compressionLevel = g_compressionLevel_default;
+    if (compressionLevel==0) compressionLevel = ZSTD_CLEVEL_DEFAULT;
     params = ZSTD_getParams(compressionLevel, averageSampleSize, dictBufferSize);
 
     esr.dict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dct_rawContent, params.cParams, ZSTD_defaultCMem);
@@ -786,7 +790,7 @@ static size_t ZDICT_analyzeEntropy(void*  dstBuffer, size_t maxDstSize,
     /* note : the result of this phase should be used to better appreciate the impact on statistics */
 
     total=0; for (u=0; u<=offcodeMax; u++) total+=offcodeCount[u];
-    errorCode = FSE_normalizeCount(offcodeNCount, Offlog, offcodeCount, total, offcodeMax);
+    errorCode = FSE_normalizeCount(offcodeNCount, Offlog, offcodeCount, total, offcodeMax, /* useLowProbCount */ 1);
     if (FSE_isError(errorCode)) {
         eSize = errorCode;
         DISPLAYLEVEL(1, "FSE_normalizeCount error with offcodeCount \n");
@@ -795,7 +799,7 @@ static size_t ZDICT_analyzeEntropy(void*  dstBuffer, size_t maxDstSize,
     Offlog = (U32)errorCode;
 
     total=0; for (u=0; u<=MaxML; u++) total+=matchLengthCount[u];
-    errorCode = FSE_normalizeCount(matchLengthNCount, mlLog, matchLengthCount, total, MaxML);
+    errorCode = FSE_normalizeCount(matchLengthNCount, mlLog, matchLengthCount, total, MaxML, /* useLowProbCount */ 1);
     if (FSE_isError(errorCode)) {
         eSize = errorCode;
         DISPLAYLEVEL(1, "FSE_normalizeCount error with matchLengthCount \n");
@@ -804,7 +808,7 @@ static size_t ZDICT_analyzeEntropy(void*  dstBuffer, size_t maxDstSize,
     mlLog = (U32)errorCode;
 
     total=0; for (u=0; u<=MaxLL; u++) total+=litLengthCount[u];
-    errorCode = FSE_normalizeCount(litLengthNCount, llLog, litLengthCount, total, MaxLL);
+    errorCode = FSE_normalizeCount(litLengthNCount, llLog, litLengthCount, total, MaxLL, /* useLowProbCount */ 1);
     if (FSE_isError(errorCode)) {
         eSize = errorCode;
         DISPLAYLEVEL(1, "FSE_normalizeCount error with litLengthCount \n");
@@ -893,7 +897,7 @@ size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity,
     size_t hSize;
 #define HBUFFSIZE 256   /* should prove large enough for all entropy headers */
     BYTE header[HBUFFSIZE];
-    int const compressionLevel = (params.compressionLevel == 0) ? g_compressionLevel_default : params.compressionLevel;
+    int const compressionLevel = (params.compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : params.compressionLevel;
     U32 const notificationLevel = params.notificationLevel;
 
     /* check conditions */
@@ -939,7 +943,7 @@ static size_t ZDICT_addEntropyTablesFromBuffer_advanced(
         const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
         ZDICT_params_t params)
 {
-    int const compressionLevel = (params.compressionLevel == 0) ? g_compressionLevel_default : params.compressionLevel;
+    int const compressionLevel = (params.compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : params.compressionLevel;
     U32 const notificationLevel = params.notificationLevel;
     size_t hSize = 8;
 
@@ -968,16 +972,11 @@ static size_t ZDICT_addEntropyTablesFromBuffer_advanced(
     return MIN(dictBufferCapacity, hSize+dictContentSize);
 }
 
-/* Hidden declaration for dbio.c */
-size_t ZDICT_trainFromBuffer_unsafe_legacy(
-                            void* dictBuffer, size_t maxDictSize,
-                            const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
-                            ZDICT_legacy_params_t params);
 /*! ZDICT_trainFromBuffer_unsafe_legacy() :
-*   Warning : `samplesBuffer` must be followed by noisy guard band.
+*   Warning : `samplesBuffer` must be followed by noisy guard band !!!
 *   @return : size of dictionary, or an error code which can be tested with ZDICT_isError()
 */
-size_t ZDICT_trainFromBuffer_unsafe_legacy(
+static size_t ZDICT_trainFromBuffer_unsafe_legacy(
                             void* dictBuffer, size_t maxDictSize,
                             const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
                             ZDICT_legacy_params_t params)
@@ -1114,8 +1113,8 @@ size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity,
     memset(&params, 0, sizeof(params));
     params.d = 8;
     params.steps = 4;
-    /* Default to level 6 since no compression level information is available */
-    params.zParams.compressionLevel = 3;
+    /* Use default level since no compression level information is available */
+    params.zParams.compressionLevel = ZSTD_CLEVEL_DEFAULT;
 #if defined(DEBUGLEVEL) && (DEBUGLEVEL>=1)
     params.zParams.notificationLevel = DEBUGLEVEL;
 #endif
similarity index 70%
rename from Utilities/cmzstd/lib/dictBuilder/zdict.h
rename to Utilities/cmzstd/lib/zdict.h
index ff2e77f..75b05db 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -36,6 +36,145 @@ extern "C" {
 #  define ZDICTLIB_API ZDICTLIB_VISIBILITY
 #endif
 
+/*******************************************************************************
+ * Zstd dictionary builder
+ *
+ * FAQ
+ * ===
+ * Why should I use a dictionary?
+ * ------------------------------
+ *
+ * Zstd can use dictionaries to improve compression ratio of small data.
+ * Traditionally small files don't compress well because there is very little
+ * repetion in a single sample, since it is small. But, if you are compressing
+ * many similar files, like a bunch of JSON records that share the same
+ * structure, you can train a dictionary on ahead of time on some samples of
+ * these files. Then, zstd can use the dictionary to find repetitions that are
+ * present across samples. This can vastly improve compression ratio.
+ *
+ * When is a dictionary useful?
+ * ----------------------------
+ *
+ * Dictionaries are useful when compressing many small files that are similar.
+ * The larger a file is, the less benefit a dictionary will have. Generally,
+ * we don't expect dictionary compression to be effective past 100KB. And the
+ * smaller a file is, the more we would expect the dictionary to help.
+ *
+ * How do I use a dictionary?
+ * --------------------------
+ *
+ * Simply pass the dictionary to the zstd compressor with
+ * `ZSTD_CCtx_loadDictionary()`. The same dictionary must then be passed to
+ * the decompressor, using `ZSTD_DCtx_loadDictionary()`. There are other
+ * more advanced functions that allow selecting some options, see zstd.h for
+ * complete documentation.
+ *
+ * What is a zstd dictionary?
+ * --------------------------
+ *
+ * A zstd dictionary has two pieces: Its header, and its content. The header
+ * contains a magic number, the dictionary ID, and entropy tables. These
+ * entropy tables allow zstd to save on header costs in the compressed file,
+ * which really matters for small data. The content is just bytes, which are
+ * repeated content that is common across many samples.
+ *
+ * What is a raw content dictionary?
+ * ---------------------------------
+ *
+ * A raw content dictionary is just bytes. It doesn't have a zstd dictionary
+ * header, a dictionary ID, or entropy tables. Any buffer is a valid raw
+ * content dictionary.
+ *
+ * How do I train a dictionary?
+ * ----------------------------
+ *
+ * Gather samples from your use case. These samples should be similar to each
+ * other. If you have several use cases, you could try to train one dictionary
+ * per use case.
+ *
+ * Pass those samples to `ZDICT_trainFromBuffer()` and that will train your
+ * dictionary. There are a few advanced versions of this function, but this
+ * is a great starting point. If you want to further tune your dictionary
+ * you could try `ZDICT_optimizeTrainFromBuffer_cover()`. If that is too slow
+ * you can try `ZDICT_optimizeTrainFromBuffer_fastCover()`.
+ *
+ * If the dictionary training function fails, that is likely because you
+ * either passed too few samples, or a dictionary would not be effective
+ * for your data. Look at the messages that the dictionary trainer printed,
+ * if it doesn't say too few samples, then a dictionary would not be effective.
+ *
+ * How large should my dictionary be?
+ * ----------------------------------
+ *
+ * A reasonable dictionary size, the `dictBufferCapacity`, is about 100KB.
+ * The zstd CLI defaults to a 110KB dictionary. You likely don't need a
+ * dictionary larger than that. But, most use cases can get away with a
+ * smaller dictionary. The advanced dictionary builders can automatically
+ * shrink the dictionary for you, and select a the smallest size that
+ * doesn't hurt compression ratio too much. See the `shrinkDict` parameter.
+ * A smaller dictionary can save memory, and potentially speed up
+ * compression.
+ *
+ * How many samples should I provide to the dictionary builder?
+ * ------------------------------------------------------------
+ *
+ * We generally recommend passing ~100x the size of the dictionary
+ * in samples. A few thousand should suffice. Having too few samples
+ * can hurt the dictionaries effectiveness. Having more samples will
+ * only improve the dictionaries effectiveness. But having too many
+ * samples can slow down the dictionary builder.
+ *
+ * How do I determine if a dictionary will be effective?
+ * -----------------------------------------------------
+ *
+ * Simply train a dictionary and try it out. You can use zstd's built in
+ * benchmarking tool to test the dictionary effectiveness.
+ *
+ *   # Benchmark levels 1-3 without a dictionary
+ *   zstd -b1e3 -r /path/to/my/files
+ *   # Benchmark levels 1-3 with a dictioanry
+ *   zstd -b1e3 -r /path/to/my/files -D /path/to/my/dictionary
+ *
+ * When should I retrain a dictionary?
+ * -----------------------------------
+ *
+ * You should retrain a dictionary when its effectiveness drops. Dictionary
+ * effectiveness drops as the data you are compressing changes. Generally, we do
+ * expect dictionaries to "decay" over time, as your data changes, but the rate
+ * at which they decay depends on your use case. Internally, we regularly
+ * retrain dictionaries, and if the new dictionary performs significantly
+ * better than the old dictionary, we will ship the new dictionary.
+ *
+ * I have a raw content dictionary, how do I turn it into a zstd dictionary?
+ * -------------------------------------------------------------------------
+ *
+ * If you have a raw content dictionary, e.g. by manually constructing it, or
+ * using a third-party dictionary builder, you can turn it into a zstd
+ * dictionary by using `ZDICT_finalizeDictionary()`. You'll also have to
+ * provide some samples of the data. It will add the zstd header to the
+ * raw content, which contains a dictionary ID and entropy tables, which
+ * will improve compression ratio, and allow zstd to write the dictionary ID
+ * into the frame, if you so choose.
+ *
+ * Do I have to use zstd's dictionary builder?
+ * -------------------------------------------
+ *
+ * No! You can construct dictionary content however you please, it is just
+ * bytes. It will always be valid as a raw content dictionary. If you want
+ * a zstd dictionary, which can improve compression ratio, use
+ * `ZDICT_finalizeDictionary()`.
+ *
+ * What is the attack surface of a zstd dictionary?
+ * ------------------------------------------------
+ *
+ * Zstd is heavily fuzz tested, including loading fuzzed dictionaries, so
+ * zstd should never crash, or access out-of-bounds memory no matter what
+ * the dictionary is. However, if an attacker can control the dictionary
+ * during decompression, they can cause zstd to generate arbitrary bytes,
+ * just like if they controlled the compressed data.
+ *
+ ******************************************************************************/
+
 
 /*! ZDICT_trainFromBuffer():
  *  Train a dictionary from an array of samples.
@@ -64,7 +203,14 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCap
 typedef struct {
     int      compressionLevel;   /*< optimize for a specific zstd compression level; 0 means default */
     unsigned notificationLevel;  /*< Write log to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */
-    unsigned dictID;             /*< force dictID value; 0 means auto mode (32-bits random value) */
+    unsigned dictID;             /*< force dictID value; 0 means auto mode (32-bits random value)
+                                  *   NOTE: The zstd format reserves some dictionary IDs for future use.
+                                  *         You may use them in private settings, but be warned that they
+                                  *         may be used by zstd in a public dictionary registry in the future.
+                                  *         These dictionary IDs are:
+                                  *           - low range  : <= 32767
+                                  *           - high range : >= (2^31)
+                                  */
 } ZDICT_params_t;
 
 /*! ZDICT_finalizeDictionary():
@@ -264,10 +410,11 @@ typedef struct {
  *  Note: ZDICT_trainFromBuffer_legacy() will send notifications into stderr if instructed to, using notificationLevel>0.
  */
 ZDICTLIB_API size_t ZDICT_trainFromBuffer_legacy(
-    void *dictBuffer, size_t dictBufferCapacity,
-    const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
+    voiddictBuffer, size_t dictBufferCapacity,
+    const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
     ZDICT_legacy_params_t parameters);
 
+
 /* Deprecation warnings */
 /* It is generally possible to disable deprecation warnings from compiler,
    for example with -Wno-deprecated-declarations for gcc
@@ -279,7 +426,7 @@ ZDICTLIB_API size_t ZDICT_trainFromBuffer_legacy(
 #  define ZDICT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
 #  if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
 #    define ZDICT_DEPRECATED(message) [[deprecated(message)]] ZDICTLIB_API
-#  elif (ZDICT_GCC_VERSION >= 405) || defined(__clang__)
+#  elif defined(__clang__) || (ZDICT_GCC_VERSION >= 405)
 #    define ZDICT_DEPRECATED(message) ZDICTLIB_API __attribute__((deprecated(message)))
 #  elif (ZDICT_GCC_VERSION >= 301)
 #    define ZDICT_DEPRECATED(message) ZDICTLIB_API __attribute__((deprecated))
index 8c6fc6a..4651e6c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -71,17 +71,22 @@ extern "C" {
 
 /*------   Version   ------*/
 #define ZSTD_VERSION_MAJOR    1
-#define ZSTD_VERSION_MINOR    4
-#define ZSTD_VERSION_RELEASE  5
-
+#define ZSTD_VERSION_MINOR    5
+#define ZSTD_VERSION_RELEASE  0
 #define ZSTD_VERSION_NUMBER  (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
-ZSTDLIB_API unsigned ZSTD_versionNumber(void);   /**< to check runtime library version */
+
+/*! ZSTD_versionNumber() :
+ *  Return runtime library version, the value is (MAJOR*100*100 + MINOR*100 + RELEASE). */
+ZSTDLIB_API unsigned ZSTD_versionNumber(void);
 
 #define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE
 #define ZSTD_QUOTE(str) #str
 #define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str)
 #define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION)
-ZSTDLIB_API const char* ZSTD_versionString(void);   /* requires v1.3.0+ */
+
+/*! ZSTD_versionString() :
+ *  Return runtime library version, like "1.4.5". Requires v1.3.0+. */
+ZSTDLIB_API const char* ZSTD_versionString(void);
 
 /* *************************************
  *  Default constant
@@ -104,7 +109,6 @@ ZSTDLIB_API const char* ZSTD_versionString(void);   /* requires v1.3.0+ */
 #define ZSTD_BLOCKSIZE_MAX     (1<<ZSTD_BLOCKSIZELOG_MAX)
 
 
-
 /***************************************
 *  Simple API
 ***************************************/
@@ -161,7 +165,7 @@ ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t
  * @return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise. */
 ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
 
-/*! ZSTD_findFrameCompressedSize() :
+/*! ZSTD_findFrameCompressedSize() : Requires v1.4.0+
  * `src` should point to the start of a ZSTD frame or skippable frame.
  * `srcSize` must be >= first frame size
  * @return : the compressed size of the first frame starting at `src`,
@@ -175,8 +179,9 @@ ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize)
 ZSTDLIB_API size_t      ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */
 ZSTDLIB_API unsigned    ZSTD_isError(size_t code);          /*!< tells if a `size_t` function result is an error code */
 ZSTDLIB_API const char* ZSTD_getErrorName(size_t code);     /*!< provides readable string from an error code */
-ZSTDLIB_API int         ZSTD_minCLevel(void);               /*!< minimum negative compression level allowed */
+ZSTDLIB_API int         ZSTD_minCLevel(void);               /*!< minimum negative compression level allowed, requires v1.4.0+ */
 ZSTDLIB_API int         ZSTD_maxCLevel(void);               /*!< maximum compression level available */
+ZSTDLIB_API int         ZSTD_defaultCLevel(void);           /*!< default compression level, specified by ZSTD_CLEVEL_DEFAULT, requires v1.5.0+ */
 
 
 /***************************************
@@ -194,7 +199,7 @@ ZSTDLIB_API int         ZSTD_maxCLevel(void);               /*!< maximum compres
  */
 typedef struct ZSTD_CCtx_s ZSTD_CCtx;
 ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void);
-ZSTDLIB_API size_t     ZSTD_freeCCtx(ZSTD_CCtx* cctx);
+ZSTDLIB_API size_t     ZSTD_freeCCtx(ZSTD_CCtx* cctx);  /* accept NULL pointer */
 
 /*! ZSTD_compressCCtx() :
  *  Same as ZSTD_compress(), using an explicit ZSTD_CCtx.
@@ -217,7 +222,7 @@ ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
  *  Use one context per thread for parallel execution. */
 typedef struct ZSTD_DCtx_s ZSTD_DCtx;
 ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void);
-ZSTDLIB_API size_t     ZSTD_freeDCtx(ZSTD_DCtx* dctx);
+ZSTDLIB_API size_t     ZSTD_freeDCtx(ZSTD_DCtx* dctx);  /* accept NULL pointer */
 
 /*! ZSTD_decompressDCtx() :
  *  Same as ZSTD_decompress(),
@@ -229,9 +234,9 @@ ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx,
                                  const void* src, size_t srcSize);
 
 
-/***************************************
-*  Advanced compression API
-***************************************/
+/*********************************************
+*  Advanced compression API (Requires v1.4.0+)
+**********************************************/
 
 /* API design :
  *   Parameters are pushed one by one into an existing context,
@@ -261,7 +266,6 @@ typedef enum { ZSTD_fast=1,
                          Only the order (from fast to strong) is guaranteed */
 } ZSTD_strategy;
 
-
 typedef enum {
 
     /* compression parameters
@@ -327,14 +331,15 @@ typedef enum {
                               * The higher the value of selected strategy, the more complex it is,
                               * resulting in stronger and slower compression.
                               * Special: value 0 means "use default strategy". */
-
     /* LDM mode parameters */
     ZSTD_c_enableLongDistanceMatching=160, /* Enable long distance matching.
                                      * This parameter is designed to improve compression ratio
                                      * for large inputs, by finding large matches at long distance.
                                      * It increases memory usage and window size.
                                      * Note: enabling this parameter increases default ZSTD_c_windowLog to 128 MB
-                                     * except when expressly set to a different value. */
+                                     * except when expressly set to a different value.
+                                     * Note: will be enabled by default if ZSTD_c_windowLog >= 128 MB and
+                                     * compression strategy >= ZSTD_btopt (== compression level 16+) */
     ZSTD_c_ldmHashLog=161,   /* Size of the table for long distance matching, as a power of 2.
                               * Larger values increase memory usage and compression ratio,
                               * but decrease compression speed.
@@ -365,20 +370,24 @@ typedef enum {
     ZSTD_c_dictIDFlag=202,   /* When applicable, dictionary's ID is written into frame header (default:1) */
 
     /* multi-threading parameters */
-    /* These parameters are only useful if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD).
-     * They return an error otherwise. */
+    /* These parameters are only active if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD).
+     * Otherwise, trying to set any other value than default (0) will be a no-op and return an error.
+     * In a situation where it's unknown if the linked library supports multi-threading or not,
+     * setting ZSTD_c_nbWorkers to any value >= 1 and consulting the return value provides a quick way to check this property.
+     */
     ZSTD_c_nbWorkers=400,    /* Select how many threads will be spawned to compress in parallel.
-                              * When nbWorkers >= 1, triggers asynchronous mode when used with ZSTD_compressStream*() :
+                              * When nbWorkers >= 1, triggers asynchronous mode when invoking ZSTD_compressStream*() :
                               * ZSTD_compressStream*() consumes input and flush output if possible, but immediately gives back control to caller,
-                              * while compression work is performed in parallel, within worker threads.
+                              * while compression is performed in parallel, within worker thread(s).
                               * (note : a strong exception to this rule is when first invocation of ZSTD_compressStream2() sets ZSTD_e_end :
                               *  in which case, ZSTD_compressStream2() delegates to ZSTD_compress2(), which is always a blocking call).
                               * More workers improve speed, but also increase memory usage.
-                              * Default value is `0`, aka "single-threaded mode" : no worker is spawned, compression is performed inside Caller's thread, all invocations are blocking */
+                              * Default value is `0`, aka "single-threaded mode" : no worker is spawned,
+                              * compression is performed inside Caller's thread, and all invocations are blocking */
     ZSTD_c_jobSize=401,      /* Size of a compression job. This value is enforced only when nbWorkers >= 1.
                               * Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads.
                               * 0 means default, which is dynamically determined based on compression parameters.
-                              * Job size must be a minimum of overlap size, or 1 MB, whichever is largest.
+                              * Job size must be a minimum of overlap size, or ZSTDMT_JOBSIZE_MIN (= 512 KB), whichever is largest.
                               * The minimum size is automatically and transparently enforced. */
     ZSTD_c_overlapLog=402,   /* Control the overlap size, as a fraction of window size.
                               * The overlap size is an amount of data reloaded from previous job at the beginning of a new job.
@@ -403,6 +412,13 @@ typedef enum {
      * ZSTD_c_literalCompressionMode
      * ZSTD_c_targetCBlockSize
      * ZSTD_c_srcSizeHint
+     * ZSTD_c_enableDedicatedDictSearch
+     * ZSTD_c_stableInBuffer
+     * ZSTD_c_stableOutBuffer
+     * ZSTD_c_blockDelimiters
+     * ZSTD_c_validateSequences
+     * ZSTD_c_splitBlocks
+     * ZSTD_c_useRowMatchFinder
      * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
      * note : never ever use experimentalParam? names directly;
      *        also, the enums values themselves are unstable and can still change.
@@ -413,7 +429,15 @@ typedef enum {
      ZSTD_c_experimentalParam4=1001,
      ZSTD_c_experimentalParam5=1002,
      ZSTD_c_experimentalParam6=1003,
-     ZSTD_c_experimentalParam7=1004
+     ZSTD_c_experimentalParam7=1004,
+     ZSTD_c_experimentalParam8=1005,
+     ZSTD_c_experimentalParam9=1006,
+     ZSTD_c_experimentalParam10=1007,
+     ZSTD_c_experimentalParam11=1008,
+     ZSTD_c_experimentalParam12=1009,
+     ZSTD_c_experimentalParam13=1010,
+     ZSTD_c_experimentalParam14=1011,
+     ZSTD_c_experimentalParam15=1012
 } ZSTD_cParameter;
 
 typedef struct {
@@ -498,9 +522,9 @@ ZSTDLIB_API size_t ZSTD_compress2( ZSTD_CCtx* cctx,
                              const void* src, size_t srcSize);
 
 
-/***************************************
-*  Advanced decompression API
-***************************************/
+/***********************************************
+*  Advanced decompression API (Requires v1.4.0+)
+************************************************/
 
 /* The advanced API pushes parameters one by one into an existing DCtx context.
  * Parameters are sticky, and remain valid for all following frames
@@ -524,11 +548,15 @@ typedef enum {
      * At the time of this writing, they include :
      * ZSTD_d_format
      * ZSTD_d_stableOutBuffer
+     * ZSTD_d_forceIgnoreChecksum
+     * ZSTD_d_refMultipleDDicts
      * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
      * note : never ever use experimentalParam? names directly
      */
      ZSTD_d_experimentalParam1=1000,
-     ZSTD_d_experimentalParam2=1001
+     ZSTD_d_experimentalParam2=1001,
+     ZSTD_d_experimentalParam3=1002,
+     ZSTD_d_experimentalParam4=1003
 
 } ZSTD_dParameter;
 
@@ -642,7 +670,7 @@ typedef ZSTD_CCtx ZSTD_CStream;  /**< CCtx and CStream are now effectively same
                                  /* Continue to distinguish them for compatibility with older versions <= v1.2.0 */
 /*===== ZSTD_CStream management functions =====*/
 ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void);
-ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs);
+ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs);  /* accept NULL pointer */
 
 /*===== Streaming compression functions =====*/
 typedef enum {
@@ -658,14 +686,15 @@ typedef enum {
                         : note : multithreaded compression will block to flush as much output as possible. */
 } ZSTD_EndDirective;
 
-/*! ZSTD_compressStream2() :
+/*! ZSTD_compressStream2() : Requires v1.4.0+
  *  Behaves about the same as ZSTD_compressStream, with additional control on end directive.
  *  - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*()
  *  - Compression parameters cannot be changed once compression is started (save a list of exceptions in multi-threading mode)
  *  - output->pos must be <= dstCapacity, input->pos must be <= srcSize
  *  - output->pos and input->pos will be updated. They are guaranteed to remain below their respective limit.
+ *  - endOp must be a valid directive
  *  - When nbWorkers==0 (default), function is blocking : it completes its job before returning to caller.
- *  - When nbWorkers>=1, function is non-blocking : it just acquires a copy of input, and distributes jobs to internal worker threads, flush whatever is available,
+ *  - When nbWorkers>=1, function is non-blocking : it copies a portion of input, distributes jobs to internal worker threads, flush to output whatever is available,
  *                                                  and then immediately returns, just indicating that there is some data remaining to be flushed.
  *                                                  The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte.
  *  - Exception : if the first call requests a ZSTD_e_end directive and provides enough dstCapacity, the function delegates to ZSTD_compress2() which is always blocking.
@@ -703,11 +732,11 @@ ZSTDLIB_API size_t ZSTD_CStreamOutSize(void);   /**< recommended size for output
 
 
 /* *****************************************************************************
- * This following is a legacy streaming API.
+ * This following is a legacy streaming API, available since v1.0+ .
  * It can be replaced by ZSTD_CCtx_reset() and ZSTD_compressStream2().
  * It is redundant, but remains fully supported.
- * Advanced parameters and dictionary compression can only be used through the
- * new API.
+ * Streaming in combination with advanced parameters and dictionary compression
+ * can only be used through the new API.
  ******************************************************************************/
 
 /*!
@@ -762,7 +791,7 @@ typedef ZSTD_DCtx ZSTD_DStream;  /**< DCtx and DStream are now effectively same
                                  /* For compatibility with versions <= v1.2.0, prefer differentiating them. */
 /*===== ZSTD_DStream management functions =====*/
 ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void);
-ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds);
+ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds);  /* accept NULL pointer */
 
 /*===== Streaming decompression functions =====*/
 
@@ -785,7 +814,7 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void);   /*!< recommended size for output
 /*! ZSTD_compress_usingDict() :
  *  Compression at an explicit compression level using a Dictionary.
  *  A dictionary can be any arbitrary data segment (also called a prefix),
- *  or a buffer with specified information (see dictBuilder/zdict.h).
+ *  or a buffer with specified information (see zdict.h).
  *  Note : This function loads the dictionary, resulting in significant startup delay.
  *         It's intended for a dictionary used only once.
  *  Note 2 : When `dict == NULL || dictSize < 8` no dictionary is used. */
@@ -828,7 +857,8 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize
                                          int compressionLevel);
 
 /*! ZSTD_freeCDict() :
- *  Function frees memory allocated by ZSTD_createCDict(). */
+ *  Function frees memory allocated by ZSTD_createCDict().
+ *  If a NULL pointer is passed, no operation is performed. */
 ZSTDLIB_API size_t      ZSTD_freeCDict(ZSTD_CDict* CDict);
 
 /*! ZSTD_compress_usingCDict() :
@@ -850,7 +880,8 @@ typedef struct ZSTD_DDict_s ZSTD_DDict;
 ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize);
 
 /*! ZSTD_freeDDict() :
- *  Function frees memory allocated with ZSTD_createDDict() */
+ *  Function frees memory allocated with ZSTD_createDDict()
+ *  If a NULL pointer is passed, no operation is performed. */
 ZSTDLIB_API size_t      ZSTD_freeDDict(ZSTD_DDict* ddict);
 
 /*! ZSTD_decompress_usingDDict() :
@@ -866,19 +897,25 @@ ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
  *  Dictionary helper functions
  *******************************/
 
-/*! ZSTD_getDictID_fromDict() :
+/*! ZSTD_getDictID_fromDict() : Requires v1.4.0+
  *  Provides the dictID stored within dictionary.
  *  if @return == 0, the dictionary is not conformant with Zstandard specification.
  *  It can still be loaded, but as a content-only dictionary. */
 ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize);
 
-/*! ZSTD_getDictID_fromDDict() :
+/*! ZSTD_getDictID_fromCDict() : Requires v1.5.0+
+ *  Provides the dictID of the dictionary loaded into `cdict`.
+ *  If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
+ *  Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
+ZSTDLIB_API unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict);
+
+/*! ZSTD_getDictID_fromDDict() : Requires v1.4.0+
  *  Provides the dictID of the dictionary loaded into `ddict`.
  *  If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
  *  Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
 ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict);
 
-/*! ZSTD_getDictID_fromFrame() :
+/*! ZSTD_getDictID_fromFrame() : Requires v1.4.0+
  *  Provides the dictID required to decompressed the frame stored within `src`.
  *  If @return == 0, the dictID could not be decoded.
  *  This could for one of the following reasons :
@@ -892,7 +929,7 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
 
 
 /*******************************************************************************
- * Advanced dictionary and prefix API
+ * Advanced dictionary and prefix API (Requires v1.4.0+)
  *
  * This API allows dictionaries to be used with ZSTD_compress2(),
  * ZSTD_compressStream2(), and ZSTD_decompress(). Dictionaries are sticky, and
@@ -901,7 +938,7 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
  ******************************************************************************/
 
 
-/*! ZSTD_CCtx_loadDictionary() :
+/*! ZSTD_CCtx_loadDictionary() : Requires v1.4.0+
  *  Create an internal CDict from `dict` buffer.
  *  Decompression will have to use same dictionary.
  * @result : 0, or an error code (which can be tested with ZSTD_isError()).
@@ -920,11 +957,11 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
  *           to precisely select how dictionary content must be interpreted. */
 ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize);
 
-/*! ZSTD_CCtx_refCDict() :
+/*! ZSTD_CCtx_refCDict() : Requires v1.4.0+
  *  Reference a prepared dictionary, to be used for all next compressed frames.
  *  Note that compression parameters are enforced from within CDict,
  *  and supersede any compression parameter previously set within CCtx.
- *  The parameters ignored are labled as "superseded-by-cdict" in the ZSTD_cParameter enum docs.
+ *  The parameters ignored are labelled as "superseded-by-cdict" in the ZSTD_cParameter enum docs.
  *  The ignored parameters will be used again if the CCtx is returned to no-dictionary mode.
  *  The dictionary will remain valid for future compressed frames using same CCtx.
  * @result : 0, or an error code (which can be tested with ZSTD_isError()).
@@ -934,7 +971,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s
  *  Note 2 : CDict is just referenced, its lifetime must outlive its usage within CCtx. */
 ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
 
-/*! ZSTD_CCtx_refPrefix() :
+/*! ZSTD_CCtx_refPrefix() : Requires v1.4.0+
  *  Reference a prefix (single-usage dictionary) for next compressed frame.
  *  A prefix is **only used once**. Tables are discarded at end of frame (ZSTD_e_end).
  *  Decompression will need same prefix to properly regenerate data.
@@ -955,7 +992,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict);
 ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx,
                                  const void* prefix, size_t prefixSize);
 
-/*! ZSTD_DCtx_loadDictionary() :
+/*! ZSTD_DCtx_loadDictionary() : Requires v1.4.0+
  *  Create an internal DDict from dict buffer,
  *  to be used to decompress next frames.
  *  The dictionary remains valid for all future frames, until explicitly invalidated.
@@ -972,9 +1009,16 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx,
  */
 ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);
 
-/*! ZSTD_DCtx_refDDict() :
+/*! ZSTD_DCtx_refDDict() : Requires v1.4.0+
  *  Reference a prepared dictionary, to be used to decompress next frames.
  *  The dictionary remains active for decompression of future frames using same DCtx.
+ *
+ *  If called with ZSTD_d_refMultipleDDicts enabled, repeated calls of this function
+ *  will store the DDict references in a table, and the DDict used for decompression
+ *  will be determined at decompression time, as per the dict ID in the frame.
+ *  The memory for the table is allocated on the first call to refDDict, and can be
+ *  freed with ZSTD_freeDCtx().
+ *
  * @result : 0, or an error code (which can be tested with ZSTD_isError()).
  *  Note 1 : Currently, only one dictionary can be managed.
  *           Referencing a new dictionary effectively "discards" any previous one.
@@ -983,7 +1027,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, s
  */
 ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict);
 
-/*! ZSTD_DCtx_refPrefix() :
+/*! ZSTD_DCtx_refPrefix() : Requires v1.4.0+
  *  Reference a prefix (single-usage dictionary) to decompress next frame.
  *  This is the reverse operation of ZSTD_CCtx_refPrefix(),
  *  and must use the same prefix as the one used during compression.
@@ -1004,7 +1048,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx,
 
 /* ===   Memory management   === */
 
-/*! ZSTD_sizeof_*() :
+/*! ZSTD_sizeof_*() : Requires v1.4.0+
  *  These functions give the _current_ memory usage of selected object.
  *  Note that object memory usage can evolve (increase or decrease) over time. */
 ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
@@ -1029,6 +1073,28 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
 #if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY)
 #define ZSTD_H_ZSTD_STATIC_LINKING_ONLY
 
+/* Deprecation warnings :
+ * Should these warnings be a problem, it is generally possible to disable them,
+ * typically with -Wno-deprecated-declarations for gcc or _CRT_SECURE_NO_WARNINGS in Visual.
+ * Otherwise, it's also possible to define ZSTD_DISABLE_DEPRECATE_WARNINGS.
+ */
+#ifdef ZSTD_DISABLE_DEPRECATE_WARNINGS
+#  define ZSTD_DEPRECATED(message) ZSTDLIB_API  /* disable deprecation warnings */
+#else
+#  if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
+#    define ZSTD_DEPRECATED(message) [[deprecated(message)]] ZSTDLIB_API
+#  elif (defined(GNUC) && (GNUC > 4 || (GNUC == 4 && GNUC_MINOR >= 5))) || defined(__clang__)
+#    define ZSTD_DEPRECATED(message) ZSTDLIB_API __attribute__((deprecated(message)))
+#  elif defined(__GNUC__) && (__GNUC__ >= 3)
+#    define ZSTD_DEPRECATED(message) ZSTDLIB_API __attribute__((deprecated))
+#  elif defined(_MSC_VER)
+#    define ZSTD_DEPRECATED(message) ZSTDLIB_API __declspec(deprecated(message))
+#  else
+#    pragma message("WARNING: You need to implement ZSTD_DEPRECATED for this compiler")
+#    define ZSTD_DEPRECATED(message) ZSTDLIB_API
+#  endif
+#endif /* ZSTD_DISABLE_DEPRECATE_WARNINGS */
+
 /****************************************************************************************
  *   experimental API (static linking only)
  ****************************************************************************************
@@ -1100,21 +1166,40 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
 typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params;
 
 typedef struct {
-    unsigned int matchPos; /* Match pos in dst */
-    /* If seqDef.offset > 3, then this is seqDef.offset - 3
-     * If seqDef.offset < 3, then this is the corresponding repeat offset
-     * But if seqDef.offset < 3 and litLength == 0, this is the
-     *   repeat offset before the corresponding repeat offset
-     * And if seqDef.offset == 3 and litLength == 0, this is the
-     *   most recent repeat offset - 1
-     */
-    unsigned int offset;
-    unsigned int litLength; /* Literal length */
-    unsigned int matchLength; /* Match length */
-    /* 0 when seq not rep and seqDef.offset otherwise
-     * when litLength == 0 this will be <= 4, otherwise <= 3 like normal
-     */
-    unsigned int rep;
+    unsigned int offset;      /* The offset of the match. (NOT the same as the offset code)
+                               * If offset == 0 and matchLength == 0, this sequence represents the last
+                               * literals in the block of litLength size.
+                               */
+
+    unsigned int litLength;   /* Literal length of the sequence. */
+    unsigned int matchLength; /* Match length of the sequence. */
+
+                              /* Note: Users of this API may provide a sequence with matchLength == litLength == offset == 0.
+                               * In this case, we will treat the sequence as a marker for a block boundary.
+                               */
+
+    unsigned int rep;         /* Represents which repeat offset is represented by the field 'offset'.
+                               * Ranges from [0, 3].
+                               *
+                               * Repeat offsets are essentially previous offsets from previous sequences sorted in
+                               * recency order. For more detail, see doc/zstd_compression_format.md
+                               *
+                               * If rep == 0, then 'offset' does not contain a repeat offset.
+                               * If rep > 0:
+                               *  If litLength != 0:
+                               *      rep == 1 --> offset == repeat_offset_1
+                               *      rep == 2 --> offset == repeat_offset_2
+                               *      rep == 3 --> offset == repeat_offset_3
+                               *  If litLength == 0:
+                               *      rep == 1 --> offset == repeat_offset_2
+                               *      rep == 2 --> offset == repeat_offset_3
+                               *      rep == 3 --> offset == repeat_offset_1 - 1
+                               *
+                               * Note: This field is optional. ZSTD_generateSequences() will calculate the value of
+                               * 'rep', but repeat offsets do not necessarily need to be calculated from an external
+                               * sequence provider's perspective. For example, ZSTD_compressSequences() does not
+                               * use this 'rep' field at all (as of now).
+                               */
 } ZSTD_Sequence;
 
 typedef struct {
@@ -1157,6 +1242,18 @@ typedef enum {
 } ZSTD_format_e;
 
 typedef enum {
+    /* Note: this enum controls ZSTD_d_forceIgnoreChecksum */
+    ZSTD_d_validateChecksum = 0,
+    ZSTD_d_ignoreChecksum = 1
+} ZSTD_forceIgnoreChecksum_e;
+
+typedef enum {
+    /* Note: this enum controls ZSTD_d_refMultipleDDicts */
+    ZSTD_rmd_refSingleDDict = 0,
+    ZSTD_rmd_refMultipleDDicts = 1
+} ZSTD_refMultipleDDicts_e;
+
+typedef enum {
     /* Note: this enum and the behavior it controls are effectively internal
      * implementation details of the compressor. They are expected to continue
      * to evolve and should be considered only in the context of extremely
@@ -1204,6 +1301,11 @@ typedef enum {
   ZSTD_lcm_uncompressed = 2   /**< Always emit uncompressed literals. */
 } ZSTD_literalCompressionMode_e;
 
+typedef enum {
+  ZSTD_urm_auto = 0,                   /* Automatically determine whether or not we use row matchfinder */
+  ZSTD_urm_disableRowMatchFinder = 1,  /* Never use row matchfinder */
+  ZSTD_urm_enableRowMatchFinder = 2    /* Always use row matchfinder when applicable */
+} ZSTD_useRowMatchFinderMode_e;
 
 /***************************************
 *  Frame size functions
@@ -1237,7 +1339,7 @@ ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t
  *  `srcSize` must be the _exact_ size of this series
  *       (i.e. there should be a frame boundary at `src + srcSize`)
  *  @return : - upper-bound for the decompressed size of all data in all successive frames
- *            - if an error occured: ZSTD_CONTENTSIZE_ERROR
+ *            - if an error occurred: ZSTD_CONTENTSIZE_ERROR
  *
  *  note 1  : an error can occur if `src` contains an invalid or incorrectly formatted frame.
  *  note 2  : the upper-bound is exact when the decompressed size field is available in every ZSTD encoded frame of `src`.
@@ -1253,14 +1355,91 @@ ZSTDLIB_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcS
  *           or an error code (if srcSize is too small) */
 ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize);
 
-/*! ZSTD_getSequences() :
- * Extract sequences from the sequence store
+typedef enum {
+  ZSTD_sf_noBlockDelimiters = 0,         /* Representation of ZSTD_Sequence has no block delimiters, sequences only */
+  ZSTD_sf_explicitBlockDelimiters = 1    /* Representation of ZSTD_Sequence contains explicit block delimiters */
+} ZSTD_sequenceFormat_e;
+
+/*! ZSTD_generateSequences() :
+ * Generate sequences using ZSTD_compress2, given a source buffer.
+ *
+ * Each block will end with a dummy sequence
+ * with offset == 0, matchLength == 0, and litLength == length of last literals.
+ * litLength may be == 0, and if so, then the sequence of (of: 0 ml: 0 ll: 0)
+ * simply acts as a block delimiter.
+ *
  * zc can be used to insert custom compression params.
  * This function invokes ZSTD_compress2
- * @return : number of sequences extracted
+ *
+ * The output of this function can be fed into ZSTD_compressSequences() with CCtx
+ * setting of ZSTD_c_blockDelimiters as ZSTD_sf_explicitBlockDelimiters
+ * @return : number of sequences generated
+ */
+
+ZSTDLIB_API size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
+                                          size_t outSeqsSize, const void* src, size_t srcSize);
+
+/*! ZSTD_mergeBlockDelimiters() :
+ * Given an array of ZSTD_Sequence, remove all sequences that represent block delimiters/last literals
+ * by merging them into into the literals of the next sequence.
+ *
+ * As such, the final generated result has no explicit representation of block boundaries,
+ * and the final last literals segment is not represented in the sequences.
+ *
+ * The output of this function can be fed into ZSTD_compressSequences() with CCtx
+ * setting of ZSTD_c_blockDelimiters as ZSTD_sf_noBlockDelimiters
+ * @return : number of sequences left after merging
+ */
+ZSTDLIB_API size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize);
+
+/*! ZSTD_compressSequences() :
+ * Compress an array of ZSTD_Sequence, generated from the original source buffer, into dst.
+ * If a dictionary is included, then the cctx should reference the dict. (see: ZSTD_CCtx_refCDict(), ZSTD_CCtx_loadDictionary(), etc.)
+ * The entire source is compressed into a single frame.
+ *
+ * The compression behavior changes based on cctx params. In particular:
+ *    If ZSTD_c_blockDelimiters == ZSTD_sf_noBlockDelimiters, the array of ZSTD_Sequence is expected to contain
+ *    no block delimiters (defined in ZSTD_Sequence). Block boundaries are roughly determined based on
+ *    the block size derived from the cctx, and sequences may be split. This is the default setting.
+ *
+ *    If ZSTD_c_blockDelimiters == ZSTD_sf_explicitBlockDelimiters, the array of ZSTD_Sequence is expected to contain
+ *    block delimiters (defined in ZSTD_Sequence). Behavior is undefined if no block delimiters are provided.
+ *
+ *    If ZSTD_c_validateSequences == 0, this function will blindly accept the sequences provided. Invalid sequences cause undefined
+ *    behavior. If ZSTD_c_validateSequences == 1, then if sequence is invalid (see doc/zstd_compression_format.md for
+ *    specifics regarding offset/matchlength requirements) then the function will bail out and return an error.
+ *
+ *    In addition to the two adjustable experimental params, there are other important cctx params.
+ *    - ZSTD_c_minMatch MUST be set as less than or equal to the smallest match generated by the match finder. It has a minimum value of ZSTD_MINMATCH_MIN.
+ *    - ZSTD_c_compressionLevel accordingly adjusts the strength of the entropy coder, as it would in typical compression.
+ *    - ZSTD_c_windowLog affects offset validation: this function will return an error at higher debug levels if a provided offset
+ *      is larger than what the spec allows for a given window log and dictionary (if present). See: doc/zstd_compression_format.md
+ *
+ * Note: Repcodes are, as of now, always re-calculated within this function, so ZSTD_Sequence::rep is unused.
+ * Note 2: Once we integrate ability to ingest repcodes, the explicit block delims mode must respect those repcodes exactly,
+ *         and cannot emit an RLE block that disagrees with the repcode history
+ * @return : final compressed size or a ZSTD error.
  */
-ZSTDLIB_API size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
-    size_t outSeqsSize, const void* src, size_t srcSize);
+ZSTDLIB_API size_t ZSTD_compressSequences(ZSTD_CCtx* const cctx, void* dst, size_t dstSize,
+                                  const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
+                                  const void* src, size_t srcSize);
+
+
+/*! ZSTD_writeSkippableFrame() :
+ * Generates a zstd skippable frame containing data given by src, and writes it to dst buffer.
+ *
+ * Skippable frames begin with a a 4-byte magic number. There are 16 possible choices of magic number,
+ * ranging from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15.
+ * As such, the parameter magicVariant controls the exact skippable frame magic number variant used, so
+ * the magic number used will be ZSTD_MAGIC_SKIPPABLE_START + magicVariant.
+ *
+ * Returns an error if destination buffer is not large enough, if the source size is not representable
+ * with a 4-byte unsigned int, or if the parameter magicVariant is greater than 15 (and therefore invalid).
+ *
+ * @return : number of bytes written or a ZSTD error.
+ */
+ZSTDLIB_API size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity,
+                                            const void* src, size_t srcSize, unsigned magicVariant);
 
 
 /***************************************
@@ -1372,7 +1551,11 @@ ZSTDLIB_API const ZSTD_DDict* ZSTD_initStaticDDict(
 typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size);
 typedef void  (*ZSTD_freeFunction) (void* opaque, void* address);
 typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem;
-static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL };  /**< this constant defers to stdlib's functions */
+static
+#ifdef __GNUC__
+__attribute__((__unused__))
+#endif
+ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL };  /**< this constant defers to stdlib's functions */
 
 ZSTDLIB_API ZSTD_CCtx*    ZSTD_createCCtx_advanced(ZSTD_customMem customMem);
 ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
@@ -1385,12 +1568,38 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictS
                                                   ZSTD_compressionParameters cParams,
                                                   ZSTD_customMem customMem);
 
-ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
-                                                  ZSTD_dictLoadMethod_e dictLoadMethod,
-                                                  ZSTD_dictContentType_e dictContentType,
-                                                  ZSTD_customMem customMem);
+/* ! Thread pool :
+ * These prototypes make it possible to share a thread pool among multiple compression contexts.
+ * This can limit resources for applications with multiple threads where each one uses
+ * a threaded compression mode (via ZSTD_c_nbWorkers parameter).
+ * ZSTD_createThreadPool creates a new thread pool with a given number of threads.
+ * Note that the lifetime of such pool must exist while being used.
+ * ZSTD_CCtx_refThreadPool assigns a thread pool to a context (use NULL argument value
+ * to use an internal thread pool).
+ * ZSTD_freeThreadPool frees a thread pool, accepts NULL pointer.
+ */
+typedef struct POOL_ctx_s ZSTD_threadPool;
+ZSTDLIB_API ZSTD_threadPool* ZSTD_createThreadPool(size_t numThreads);
+ZSTDLIB_API void ZSTD_freeThreadPool (ZSTD_threadPool* pool);  /* accept NULL pointer */
+ZSTDLIB_API size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool);
 
 
+/*
+ * This API is temporary and is expected to change or disappear in the future!
+ */
+ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced2(
+    const void* dict, size_t dictSize,
+    ZSTD_dictLoadMethod_e dictLoadMethod,
+    ZSTD_dictContentType_e dictContentType,
+    const ZSTD_CCtx_params* cctxParams,
+    ZSTD_customMem customMem);
+
+ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(
+    const void* dict, size_t dictSize,
+    ZSTD_dictLoadMethod_e dictLoadMethod,
+    ZSTD_dictContentType_e dictContentType,
+    ZSTD_customMem customMem);
+
 
 /***************************************
 *  Advanced compression functions
@@ -1430,18 +1639,20 @@ ZSTDLIB_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParame
 /*! ZSTD_compress_advanced() :
  *  Note : this function is now DEPRECATED.
  *         It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_setParameter() and other parameter setters.
- *  This prototype will be marked as deprecated and generate compilation warning on reaching v1.5.x */
-ZSTDLIB_API size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx,
+ *  This prototype will generate compilation warnings. */
+ZSTD_DEPRECATED("use ZSTD_compress2")
+size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx,
                                           void* dst, size_t dstCapacity,
                                     const void* src, size_t srcSize,
                                     const void* dict,size_t dictSize,
                                           ZSTD_parameters params);
 
 /*! ZSTD_compress_usingCDict_advanced() :
- *  Note : this function is now REDUNDANT.
+ *  Note : this function is now DEPRECATED.
  *         It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_loadDictionary() and other parameter setters.
- *  This prototype will be marked as deprecated and generate compilation warning in some future version */
-ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
+ *  This prototype will generate compilation warnings. */
+ZSTD_DEPRECATED("use ZSTD_compress2 with ZSTD_CCtx_loadDictionary")
+size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
                                               void* dst, size_t dstCapacity,
                                         const void* src, size_t srcSize,
                                         const ZSTD_CDict* cdict,
@@ -1503,7 +1714,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* pre
 
 /* Controls how the literals are compressed (default is auto).
  * The value must be of type ZSTD_literalCompressionMode_e.
- * See ZSTD_literalCompressionMode_t enum definition for details.
+ * See ZSTD_literalCompressionMode_e enum definition for details.
  */
 #define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5
 
@@ -1518,12 +1729,189 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* pre
  * but compression ratio may regress significantly if guess considerably underestimates */
 #define ZSTD_c_srcSizeHint ZSTD_c_experimentalParam7
 
+/* Controls whether the new and experimental "dedicated dictionary search
+ * structure" can be used. This feature is still rough around the edges, be
+ * prepared for surprising behavior!
+ *
+ * How to use it:
+ *
+ * When using a CDict, whether to use this feature or not is controlled at
+ * CDict creation, and it must be set in a CCtxParams set passed into that
+ * construction (via ZSTD_createCDict_advanced2()). A compression will then
+ * use the feature or not based on how the CDict was constructed; the value of
+ * this param, set in the CCtx, will have no effect.
+ *
+ * However, when a dictionary buffer is passed into a CCtx, such as via
+ * ZSTD_CCtx_loadDictionary(), this param can be set on the CCtx to control
+ * whether the CDict that is created internally can use the feature or not.
+ *
+ * What it does:
+ *
+ * Normally, the internal data structures of the CDict are analogous to what
+ * would be stored in a CCtx after compressing the contents of a dictionary.
+ * To an approximation, a compression using a dictionary can then use those
+ * data structures to simply continue what is effectively a streaming
+ * compression where the simulated compression of the dictionary left off.
+ * Which is to say, the search structures in the CDict are normally the same
+ * format as in the CCtx.
+ *
+ * It is possible to do better, since the CDict is not like a CCtx: the search
+ * structures are written once during CDict creation, and then are only read
+ * after that, while the search structures in the CCtx are both read and
+ * written as the compression goes along. This means we can choose a search
+ * structure for the dictionary that is read-optimized.
+ *
+ * This feature enables the use of that different structure.
+ *
+ * Note that some of the members of the ZSTD_compressionParameters struct have
+ * different semantics and constraints in the dedicated search structure. It is
+ * highly recommended that you simply set a compression level in the CCtxParams
+ * you pass into the CDict creation call, and avoid messing with the cParams
+ * directly.
+ *
+ * Effects:
+ *
+ * This will only have any effect when the selected ZSTD_strategy
+ * implementation supports this feature. Currently, that's limited to
+ * ZSTD_greedy, ZSTD_lazy, and ZSTD_lazy2.
+ *
+ * Note that this means that the CDict tables can no longer be copied into the
+ * CCtx, so the dict attachment mode ZSTD_dictForceCopy will no longer be
+ * useable. The dictionary can only be attached or reloaded.
+ *
+ * In general, you should expect compression to be faster--sometimes very much
+ * so--and CDict creation to be slightly slower. Eventually, we will probably
+ * make this mode the default.
+ */
+#define ZSTD_c_enableDedicatedDictSearch ZSTD_c_experimentalParam8
+
+/* ZSTD_c_stableInBuffer
+ * Experimental parameter.
+ * Default is 0 == disabled. Set to 1 to enable.
+ *
+ * Tells the compressor that the ZSTD_inBuffer will ALWAYS be the same
+ * between calls, except for the modifications that zstd makes to pos (the
+ * caller must not modify pos). This is checked by the compressor, and
+ * compression will fail if it ever changes. This means the only flush
+ * mode that makes sense is ZSTD_e_end, so zstd will error if ZSTD_e_end
+ * is not used. The data in the ZSTD_inBuffer in the range [src, src + pos)
+ * MUST not be modified during compression or you will get data corruption.
+ *
+ * When this flag is enabled zstd won't allocate an input window buffer,
+ * because the user guarantees it can reference the ZSTD_inBuffer until
+ * the frame is complete. But, it will still allocate an output buffer
+ * large enough to fit a block (see ZSTD_c_stableOutBuffer). This will also
+ * avoid the memcpy() from the input buffer to the input window buffer.
+ *
+ * NOTE: ZSTD_compressStream2() will error if ZSTD_e_end is not used.
+ * That means this flag cannot be used with ZSTD_compressStream().
+ *
+ * NOTE: So long as the ZSTD_inBuffer always points to valid memory, using
+ * this flag is ALWAYS memory safe, and will never access out-of-bounds
+ * memory. However, compression WILL fail if you violate the preconditions.
+ *
+ * WARNING: The data in the ZSTD_inBuffer in the range [dst, dst + pos) MUST
+ * not be modified during compression or you will get data corruption. This
+ * is because zstd needs to reference data in the ZSTD_inBuffer to find
+ * matches. Normally zstd maintains its own window buffer for this purpose,
+ * but passing this flag tells zstd to use the user provided buffer.
+ */
+#define ZSTD_c_stableInBuffer ZSTD_c_experimentalParam9
+
+/* ZSTD_c_stableOutBuffer
+ * Experimental parameter.
+ * Default is 0 == disabled. Set to 1 to enable.
+ *
+ * Tells he compressor that the ZSTD_outBuffer will not be resized between
+ * calls. Specifically: (out.size - out.pos) will never grow. This gives the
+ * compressor the freedom to say: If the compressed data doesn't fit in the
+ * output buffer then return ZSTD_error_dstSizeTooSmall. This allows us to
+ * always decompress directly into the output buffer, instead of decompressing
+ * into an internal buffer and copying to the output buffer.
+ *
+ * When this flag is enabled zstd won't allocate an output buffer, because
+ * it can write directly to the ZSTD_outBuffer. It will still allocate the
+ * input window buffer (see ZSTD_c_stableInBuffer).
+ *
+ * Zstd will check that (out.size - out.pos) never grows and return an error
+ * if it does. While not strictly necessary, this should prevent surprises.
+ */
+#define ZSTD_c_stableOutBuffer ZSTD_c_experimentalParam10
+
+/* ZSTD_c_blockDelimiters
+ * Default is 0 == ZSTD_sf_noBlockDelimiters.
+ *
+ * For use with sequence compression API: ZSTD_compressSequences().
+ *
+ * Designates whether or not the given array of ZSTD_Sequence contains block delimiters
+ * and last literals, which are defined as sequences with offset == 0 and matchLength == 0.
+ * See the definition of ZSTD_Sequence for more specifics.
+ */
+#define ZSTD_c_blockDelimiters ZSTD_c_experimentalParam11
+
+/* ZSTD_c_validateSequences
+ * Default is 0 == disabled. Set to 1 to enable sequence validation.
+ *
+ * For use with sequence compression API: ZSTD_compressSequences().
+ * Designates whether or not we validate sequences provided to ZSTD_compressSequences()
+ * during function execution.
+ *
+ * Without validation, providing a sequence that does not conform to the zstd spec will cause
+ * undefined behavior, and may produce a corrupted block.
+ *
+ * With validation enabled, a if sequence is invalid (see doc/zstd_compression_format.md for
+ * specifics regarding offset/matchlength requirements) then the function will bail out and
+ * return an error.
+ *
+ */
+#define ZSTD_c_validateSequences ZSTD_c_experimentalParam12
+
+/* ZSTD_c_splitBlocks
+ * Default is 0 == disabled. Set to 1 to enable block splitting.
+ *
+ * Will attempt to split blocks in order to improve compression ratio at the cost of speed.
+ */
+#define ZSTD_c_splitBlocks ZSTD_c_experimentalParam13
+
+/* ZSTD_c_useRowMatchFinder
+ * Default is ZSTD_urm_auto.
+ * Controlled with ZSTD_useRowMatchFinderMode_e enum.
+ *
+ * By default, in ZSTD_urm_auto, when finalizing the compression parameters, the library
+ * will decide at runtime whether to use the row-based matchfinder based on support for SIMD
+ * instructions as well as the windowLog.
+ *
+ * Set to ZSTD_urm_disableRowMatchFinder to never use row-based matchfinder.
+ * Set to ZSTD_urm_enableRowMatchFinder to force usage of row-based matchfinder.
+ */
+#define ZSTD_c_useRowMatchFinder ZSTD_c_experimentalParam14
+
+/* ZSTD_c_deterministicRefPrefix
+ * Default is 0 == disabled. Set to 1 to enable.
+ *
+ * Zstd produces different results for prefix compression when the prefix is
+ * directly adjacent to the data about to be compressed vs. when it isn't.
+ * This is because zstd detects that the two buffers are contiguous and it can
+ * use a more efficient match finding algorithm. However, this produces different
+ * results than when the two buffers are non-contiguous. This flag forces zstd
+ * to always load the prefix in non-contiguous mode, even if it happens to be
+ * adjacent to the data, to guarantee determinism.
+ *
+ * If you really care about determinism when using a dictionary or prefix,
+ * like when doing delta compression, you should select this option. It comes
+ * at a speed penalty of about ~2.5% if the dictionary and data happened to be
+ * contiguous, and is free if they weren't contiguous. We don't expect that
+ * intentionally making the dictionary and data contiguous will be worth the
+ * cost to memcpy() the data.
+ */
+#define ZSTD_c_deterministicRefPrefix ZSTD_c_experimentalParam15
+
 /*! ZSTD_CCtx_getParameter() :
  *  Get the requested compression parameter value, selected by enum ZSTD_cParameter,
  *  and store it into int* value.
  * @return : 0, or an error code (which can be tested with ZSTD_isError()).
  */
-ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value);
+ZSTDLIB_API size_t ZSTD_CCtx_getParameter(const ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value);
 
 
 /*! ZSTD_CCtx_params :
@@ -1538,13 +1926,13 @@ ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param
  *                                    These parameters will be applied to
  *                                    all subsequent frames.
  *  - ZSTD_compressStream2() : Do compression using the CCtx.
- *  - ZSTD_freeCCtxParams() : Free the memory.
+ *  - ZSTD_freeCCtxParams() : Free the memory, accept NULL pointer.
  *
  *  This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams()
  *  for static allocation of CCtx for single-threaded compression.
  */
 ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void);
-ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);
+ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params);  /* accept NULL pointer */
 
 /*! ZSTD_CCtxParams_reset() :
  *  Reset params to default values.
@@ -1563,11 +1951,13 @@ ZSTDLIB_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compre
  */
 ZSTDLIB_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params);
 
-/*! ZSTD_CCtxParams_setParameter() :
+/*! ZSTD_CCtxParams_setParameter() : Requires v1.4.0+
  *  Similar to ZSTD_CCtx_setParameter.
  *  Set one compression parameter, selected by enum ZSTD_cParameter.
- *  Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams().
- * @result : 0, or an error code (which can be tested with ZSTD_isError()).
+ *  Parameters must be applied to a ZSTD_CCtx using
+ *  ZSTD_CCtx_setParametersUsingCCtxParams().
+ * @result : a code representing success or failure (which can be tested with
+ *           ZSTD_isError()).
  */
 ZSTDLIB_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value);
 
@@ -1576,7 +1966,7 @@ ZSTDLIB_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_c
  * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter.
  * @result : 0, or an error code (which can be tested with ZSTD_isError()).
  */
-ZSTDLIB_API size_t ZSTD_CCtxParams_getParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value);
+ZSTDLIB_API size_t ZSTD_CCtxParams_getParameter(const ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value);
 
 /*! ZSTD_CCtx_setParametersUsingCCtxParams() :
  *  Apply a set of ZSTD_CCtx_params to the compression context.
@@ -1647,6 +2037,13 @@ ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* pre
  */
 ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize);
 
+/*! ZSTD_DCtx_getParameter() :
+ *  Get the requested decompression parameter value, selected by enum ZSTD_dParameter,
+ *  and store it into int* value.
+ * @return : 0, or an error code (which can be tested with ZSTD_isError()).
+ */
+ZSTDLIB_API size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value);
+
 /* ZSTD_d_format
  * experimental parameter,
  * allowing selection between ZSTD_format_e input compression formats
@@ -1684,12 +2081,49 @@ ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowS
  */
 #define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2
 
+/* ZSTD_d_forceIgnoreChecksum
+ * Experimental parameter.
+ * Default is 0 == disabled. Set to 1 to enable
+ *
+ * Tells the decompressor to skip checksum validation during decompression, regardless
+ * of whether checksumming was specified during compression. This offers some
+ * slight performance benefits, and may be useful for debugging.
+ * Param has values of type ZSTD_forceIgnoreChecksum_e
+ */
+#define ZSTD_d_forceIgnoreChecksum ZSTD_d_experimentalParam3
+
+/* ZSTD_d_refMultipleDDicts
+ * Experimental parameter.
+ * Default is 0 == disabled. Set to 1 to enable
+ *
+ * If enabled and dctx is allocated on the heap, then additional memory will be allocated
+ * to store references to multiple ZSTD_DDict. That is, multiple calls of ZSTD_refDDict()
+ * using a given ZSTD_DCtx, rather than overwriting the previous DDict reference, will instead
+ * store all references. At decompression time, the appropriate dictID is selected
+ * from the set of DDicts based on the dictID in the frame.
+ *
+ * Usage is simply calling ZSTD_refDDict() on multiple dict buffers.
+ *
+ * Param has values of byte ZSTD_refMultipleDDicts_e
+ *
+ * WARNING: Enabling this parameter and calling ZSTD_DCtx_refDDict(), will trigger memory
+ * allocation for the hash table. ZSTD_freeDCtx() also frees this memory.
+ * Memory is allocated as per ZSTD_DCtx::customMem.
+ *
+ * Although this function allocates memory for the table, the user is still responsible for
+ * memory management of the underlying ZSTD_DDict* themselves.
+ */
+#define ZSTD_d_refMultipleDDicts ZSTD_d_experimentalParam4
+
+
 /*! ZSTD_DCtx_setFormat() :
+ *  This function is REDUNDANT. Prefer ZSTD_DCtx_setParameter().
  *  Instruct the decoder context about what kind of data to decode next.
  *  This instruction is mandatory to decode data without a fully-formed header,
  *  such ZSTD_f_zstd1_magicless for example.
  * @return : 0, or an error code (which can be tested using ZSTD_isError()). */
-ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
+ZSTD_DEPRECATED("use ZSTD_DCtx_setParameter() instead")
+size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format);
 
 /*! ZSTD_decompressStream_simpleArgs() :
  *  Same as ZSTD_decompressStream(),
@@ -1711,8 +2145,9 @@ ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs (
 ********************************************************************/
 
 /*=====   Advanced Streaming compression functions  =====*/
-/**! ZSTD_initCStream_srcSize() :
- * This function is deprecated, and equivalent to:
+
+/*! ZSTD_initCStream_srcSize() :
+ * This function is DEPRECATED, and equivalent to:
  *     ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
  *     ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any)
  *     ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel);
@@ -1721,15 +2156,15 @@ ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs (
  * pledgedSrcSize must be correct. If it is not known at init time, use
  * ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs,
  * "0" also disables frame content size field. It may be enabled in the future.
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
+ * This prototype will generate compilation warnings.
  */
-ZSTDLIB_API size_t
-ZSTD_initCStream_srcSize(ZSTD_CStream* zcs,
+ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions")
+size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs,
                          int compressionLevel,
                          unsigned long long pledgedSrcSize);
 
-/**! ZSTD_initCStream_usingDict() :
- * This function is deprecated, and is equivalent to:
+/*! ZSTD_initCStream_usingDict() :
+ * This function is DEPRECATED, and is equivalent to:
  *     ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
  *     ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel);
  *     ZSTD_CCtx_loadDictionary(zcs, dict, dictSize);
@@ -1738,15 +2173,15 @@ ZSTD_initCStream_srcSize(ZSTD_CStream* zcs,
  * dict == NULL or dictSize < 8, in which case no dict is used.
  * Note: dict is loaded with ZSTD_dct_auto (treated as a full zstd dictionary if
  * it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
+ * This prototype will generate compilation warnings.
  */
-ZSTDLIB_API size_t
-ZSTD_initCStream_usingDict(ZSTD_CStream* zcs,
+ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions")
+size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs,
                      const void* dict, size_t dictSize,
                            int compressionLevel);
 
-/**! ZSTD_initCStream_advanced() :
- * This function is deprecated, and is approximately equivalent to:
+/*! ZSTD_initCStream_advanced() :
+ * This function is DEPRECATED, and is approximately equivalent to:
  *     ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
  *     // Pseudocode: Set each zstd parameter and leave the rest as-is.
  *     for ((param, value) : params) {
@@ -1758,25 +2193,26 @@ ZSTD_initCStream_usingDict(ZSTD_CStream* zcs,
  * dict is loaded with ZSTD_dct_auto and ZSTD_dlm_byCopy.
  * pledgedSrcSize must be correct.
  * If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
+ * This prototype will generate compilation warnings.
  */
-ZSTDLIB_API size_t
-ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
+ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions")
+size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
                     const void* dict, size_t dictSize,
                           ZSTD_parameters params,
                           unsigned long long pledgedSrcSize);
 
-/**! ZSTD_initCStream_usingCDict() :
- * This function is deprecated, and equivalent to:
+/*! ZSTD_initCStream_usingCDict() :
+ * This function is DEPRECATED, and equivalent to:
  *     ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
  *     ZSTD_CCtx_refCDict(zcs, cdict);
- *
+ * 
  * note : cdict will just be referenced, and must outlive compression session
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
+ * This prototype will generate compilation warnings.
  */
-ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict);
+ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions")
+size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict);
 
-/**! ZSTD_initCStream_usingCDict_advanced() :
+/*! ZSTD_initCStream_usingCDict_advanced() :
  *   This function is DEPRECATED, and is approximately equivalent to:
  *     ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
  *     // Pseudocode: Set each zstd frame parameter and leave the rest as-is.
@@ -1789,18 +2225,21 @@ ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDi
  * same as ZSTD_initCStream_usingCDict(), with control over frame parameters.
  * pledgedSrcSize must be correct. If srcSize is not known at init time, use
  * value ZSTD_CONTENTSIZE_UNKNOWN.
- * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
+ * This prototype will generate compilation warnings.
  */
-ZSTDLIB_API size_t
-ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
+ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions")
+size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
                                const ZSTD_CDict* cdict,
                                      ZSTD_frameParameters fParams,
                                      unsigned long long pledgedSrcSize);
 
 /*! ZSTD_resetCStream() :
- * This function is deprecated, and is equivalent to:
+ * This function is DEPRECATED, and is equivalent to:
  *     ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
  *     ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize);
+ * Note: ZSTD_resetCStream() interprets pledgedSrcSize == 0 as ZSTD_CONTENTSIZE_UNKNOWN, but
+ *       ZSTD_CCtx_setPledgedSrcSize() does not do the same, so ZSTD_CONTENTSIZE_UNKNOWN must be
+ *       explicitly specified.
  *
  *  start a new frame, using same parameters from previous frame.
  *  This is typically useful to skip dictionary loading stage, since it will re-use it in-place.
@@ -1810,9 +2249,10 @@ ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
  *  For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs,
  *  but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead.
  * @return : 0, or an error code (which can be tested using ZSTD_isError())
- *  Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x
+ *  This prototype will generate compilation warnings.
  */
-ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
+ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions")
+size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
 
 
 typedef struct {
@@ -1849,7 +2289,8 @@ ZSTDLIB_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx);
 
 
 /*=====   Advanced Streaming decompression functions  =====*/
-/**
+
+/*!
  * This function is deprecated, and is equivalent to:
  *
  *     ZSTD_DCtx_reset(zds, ZSTD_reset_session_only);
@@ -1860,7 +2301,7 @@ ZSTDLIB_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx);
  */
 ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize);
 
-/**
+/*!
  * This function is deprecated, and is equivalent to:
  *
  *     ZSTD_DCtx_reset(zds, ZSTD_reset_session_only);
@@ -1871,7 +2312,7 @@ ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dic
  */
 ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);
 
-/**
+/*!
  * This function is deprecated, and is equivalent to:
  *
  *     ZSTD_DCtx_reset(zds, ZSTD_reset_session_only);
@@ -1898,8 +2339,7 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);
   ZSTD_CCtx object can be re-used multiple times within successive compression operations.
 
   Start by initializing a context.
-  Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression,
-  or ZSTD_compressBegin_advanced(), for finer parameter control.
+  Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression.
   It's also possible to duplicate a reference context which has already been initialized, using ZSTD_copyCCtx()
 
   Then, consume your input using ZSTD_compressContinue().
@@ -1924,16 +2364,18 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);
 /*=====   Buffer-less streaming compression functions  =====*/
 ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
 ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);
-ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */
 ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */
-ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize);   /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */
 ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**<  note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */
 
 ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
 ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
 
-
-/*-
+/* The ZSTD_compressBegin_advanced() and ZSTD_compressBegin_usingCDict_advanced() are now DEPRECATED and will generate a compiler warning */
+ZSTD_DEPRECATED("use advanced API to access custom parameters")
+size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */
+ZSTD_DEPRECATED("use advanced API to access custom parameters")
+size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize);   /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */
+/**
   Buffer-less streaming decompression (synchronous mode)
 
   A ZSTD_DCtx object is required to track streaming operations.
similarity index 97%
rename from Utilities/cmzstd/lib/common/zstd_errors.h
rename to Utilities/cmzstd/lib/zstd_errors.h
index 998398e..fa3686b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * Copyright (c) Yann Collet, Facebook, Inc.
  * All rights reserved.
  *
  * This source code is licensed under both the BSD-style license (found in the
@@ -77,6 +77,7 @@ typedef enum {
   ZSTD_error_frameIndex_tooLarge = 100,
   ZSTD_error_seekableIO          = 102,
   ZSTD_error_dstBuffer_wrong     = 104,
+  ZSTD_error_srcBuffer_wrong     = 105,
   ZSTD_error_maxCode = 120  /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
 } ZSTD_ErrorCode;
 
index c7fbed1..a487375 100755 (executable)
--- a/bootstrap
+++ b/bootstrap
@@ -325,6 +325,7 @@ CMAKE_CXX_SOURCES="\
   cmDefinePropertyCommand \
   cmDefinitions \
   cmDocumentationFormatter \
+  cmELF \
   cmEnableLanguageCommand \
   cmEnableTestingCommand \
   cmExecProgramCommand \
@@ -426,6 +427,7 @@ CMAKE_CXX_SOURCES="\
   cmPolicies \
   cmProcessOutput \
   cmProjectCommand \
+  cmValue \
   cmPropertyDefinition \
   cmPropertyMap \
   cmGccDepfileLexerHelper \